using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Drawing;
using SlimDX;
using SlimDX.Direct3D9;


namespace Splino.Commands
{

    using Splino.D3D;


    /// <summary>
    /// Enumerator for different types of commands
    /// used by Splino:
    /// </summary>
    public enum CommandType
    {
        /// <summary>
        /// Object commands manipulate objects, their 
        /// properties and geometry 
        /// </summary>
        ObjectCommand,

        /// <summary>
        /// Viewport commands manipulate the four
        /// Splino viewports and their cameras 
        /// </summary>
        ViewportCommand,

        /// <summary>
        /// Interface commands manipulate various
        /// settings and options
        /// </summary>
        InterfaceCommand,

        /// <summary>
        /// System commands perform behind the scenes
        /// logic and processing
        /// </summary>
        SystemCommand
    }

    /// <summary>
    /// Base class for all Splino Commands
    /// </summary>
    public class Command
    {
        /// <summary>
        /// The string name of the command used to
        /// actually call the command from the prompt
        /// </summary>
        protected String _name = "[Unknown Command]";
        /// <summary>
        /// Gets the string name of the command used to
        /// actually call the command from the prompt
        /// </summary>
        public String Name { get { return _name; } }

        /// <summary>
        /// The string name of the object the command
        /// is working on
        /// </summary>
        protected String _objectName = "";
        /// <summary>
        /// Gets the string name of the object the command
        /// is working on
        /// </summary>
        public String ObjectName { get { return _objectName; } }

        /// <summary>
        /// The concatanation of the string command name and 
        /// string name of the object the command is working on
        /// in order to differentiate the commands from similar calls
        /// </summary>
        protected String _id = "Unknown";
        /// <summary>
        /// Gets the concatanation of the string command name and 
        /// string name of the object the command is working on
        /// in order to differentiate the commands from similar calls
        /// </summary>
        public String ID { get { return _id; } }

        /// <summary>
        /// String description of what the command does,
        /// displayed in the command prompt
        /// </summary>
        protected String _description;
        /// <summary>
        /// Gets a string description of what the command does,
        /// displayed in the command prompt
        /// </summary>
        public String Description { get { return _description; } }

        /// <summary>
        /// The string usage guidlines for the command
        /// displayed in th ecommand prompt
        /// </summary>
        protected string _usage;
        /// <summary>
        /// Gets the string usage guidlines for the command
        /// displayed in th ecommand prompt
        /// </summary>
        public String Usage { get { return _usage; } }

        /// <summary>
        /// True if the command is undoable
        /// False by default
        /// </summary>
        protected bool _undoable = false;
        /// <summary>
        /// Gets if the command can be undone
        /// </summary>
        public bool Undoable { get { return _undoable; } }

        /// <summary>
        /// The type of command from the CommandType enumerator
        /// </summary>
        protected CommandType _commandType = new CommandType();
        /// <summary>
        /// Gets the type of command from the CommandType enumerator
        /// </summary>
        public CommandType CommandType { get { return _commandType; } }

        /// <summary>
        /// If true, the undo command undoes all commands while
        /// they have the same ID.  Ie: Mouse wheel zooms on a viewport
        /// </summary>
        protected bool _repeatable = false;
        /// <summary>
        /// Gets if the undo command undoes all commands while
        /// they have the same ID.  Ie: Mouse wheel zooms on a viewport
        /// </summary>
        public bool Repeatable { get { return _repeatable; } }

        /// <summary>
        /// Gets or sets which viewport panel currently has focus
        /// </summary>
        protected SplinoWindow _activeWindow = null;
        /// <summary>
        /// Gets or sets which viewport panel currently has focus
        /// </summary>
        public SplinoWindow ActiveWindow
        {
            get { return _activeWindow; }
            set { _activeWindow = value;}
        }

        /// <summary>
        /// Gets or sets which icon the cursor is currently using
        /// </summary>
        protected Cursor _activeCursor = Cursors.Default;
        /// <summary>
        /// Gets or sets which icon the cursor is currently using
        /// </summary>
        public Cursor ActiveCursor
        {
            get { return _activeCursor; }
            set { _activeCursor = value; }
        }

        /// <summary>
        /// True if user has entered sufficient input
        /// data to execute the command
        /// </summary>
        protected bool _initialized = false;

        /// <summary>
        /// Splino objects that will be passed directly to the command
        /// through the constructor.
        /// </summary>
        protected SplinoObject[] _inputObjects = null;

        /// <summary>
        /// True if the command is accepting parameters
        /// from the command line such as vectors, or objects
        /// </summary>
        protected bool _processingInput = false;
        /// <summary>
        /// Gets if the command is accepting parameters
        /// from the command line such as vectors, or objects
        /// </summary>
        public bool ProcessingInput { get { return _processingInput; } }

        // with the cursor
        /// <summary>
        /// Gets or sets whether a 3D point should be drawn
        /// </summary>
        protected bool _pointCursorActive = false;
        /// <summary>
        /// Gets or sets whether a 3D point should be drawn
        /// </summary>
        public bool PointCursorActive
        {
            get { return _pointCursorActive; }
            set { _pointCursorActive = value; }
        }

        /// <summary>
        /// Constructor
        /// </summary>
        protected Command() { }

        /// <summary>
        /// Executes the command functionality
        /// </summary>
        virtual public void Execute()
        {
            CommandManager.Instance.ActiveCommandStack.Push(this);

            if (SplinoForm.Instance.WindowMouseOver != null)
                MouseEnter(null, CommandManager.Instance.ActiveWindow.GenerateMouseEventArgs());

            if (_processingInput)
                CommandManager.Instance.WriteUsageLine(_name + ": (" + _usage + ")");

            foreach (SplinoWindow splinoWindow in SplinoForm.Instance.SplinoWindows)
            {
                splinoWindow.PresentationPanel.MouseMove += new MouseEventHandler(MouseMove);
                splinoWindow.PresentationPanel.MouseEnter += new EventHandler(MouseEnter);
                splinoWindow.PresentationPanel.MouseLeave += new EventHandler(MouseLeave);
                splinoWindow.PresentationPanel.MouseDown += new MouseEventHandler(MouseDown);
                splinoWindow.PresentationPanel.MouseUp += new MouseEventHandler(MouseUp);
                splinoWindow.PresentationPanel.MouseWheel += new MouseEventHandler(MouseWheel);
            }
        }

        /// <summary>
        /// Initializes the command, enabling its functionality
        /// for execution
        /// </summary>
        virtual public void InitializeCommand()
        {
            _initialized = true;
        }

        /// <summary>
        /// True if the user has thoroughly carried out the
        /// command, allowing it to be added to the undo stack
        /// </summary>
        protected bool _finalizable = false;

        /// <summary>
        /// Finalizes command execution, and if allowed, adds
        /// the command to the undo stack
        /// </summary>
        virtual public void FinalizeCommand()
        {
            if (_undoable)
                if (_commandType == CommandType.ViewportCommand)
                    CommandManager.Instance.AddViewCommandToUndoStack();
                else if (_finalizable)
                    CommandManager.Instance.AddObjectCommandToUndoStack();
            if (CommandManager.Instance.ActiveCommandStack.Count > 1)
                CommandManager.Instance.ActiveCommandStack.Pop();
            CommandManager.Instance.ActiveWindow.Cursor =
                CommandManager.Instance.ActiveCommandStack.Peek().ActiveCursor;
            if (_processingInput)
            {
                CommandManager.Instance.WriteUsageLine(
                    CommandManager.Instance.ActiveCommandStack.Peek().Name + ": (" +
                    CommandManager.Instance.ActiveCommandStack.Peek().Usage + ")");
            }

            foreach (SplinoWindow splinoWindow in SplinoForm.Instance.SplinoWindows)
            {
                splinoWindow.PresentationPanel.MouseMove -= new MouseEventHandler(MouseMove);
                splinoWindow.PresentationPanel.MouseEnter -= new EventHandler(MouseEnter);
                splinoWindow.PresentationPanel.MouseLeave -= new EventHandler(MouseLeave);
                splinoWindow.PresentationPanel.MouseDown -= new MouseEventHandler(MouseDown);
                splinoWindow.PresentationPanel.MouseUp -= new MouseEventHandler(MouseUp);
                splinoWindow.PresentationPanel.MouseWheel -= new MouseEventHandler(MouseWheel);
            }
        }

        /// <summary>
        /// Undoes the command
        /// </summary>
        virtual public void Undo() { }

        /// <summary>
        /// Redoes the command
        /// </summary>
        virtual public void Redo() { }

        /// <summary>
        /// Accepts an object, casts it to the desired format, and processes
        /// it as an input parameter for the command, returning true if the object
        /// was successfully used.
        /// </summary>
        /// <param name="input">An object of varying type that will be cast
        /// and used by the command</param>
        /// <param name="inputs">An array of objects of varying type that will be
        /// cast and used by the command</param>
        /// <returns>True if the input object was used properly</returns>
        virtual public bool ProcessInput(Object input, Object[] inputs) { return false; }

        /// <summary>
        /// Accepts a float and attempts to use it as an input parameter for the command,
        /// returning true if the float was successfully used.
        /// </summary>
        /// <param name="input">A float to be used by the command</param>
        /// <returns>True if the float was properly used</returns>
        virtual public bool ProcessFloat(float input) { return false; }

        /// <summary>
        /// Accepts a 2D vector and attempts to use it as an input parameter for the
        /// command, returning true if the vector was successfully used.
        /// </summary>
        /// <param name="input">A 2D vector to be used by the command</param>
        /// <returns>True if the 2D vector was properly used</returns>
        virtual public bool ProcessVector2(Vector2 input) { return false; }

        /// <summary>
        /// Accepts a 3D vector and attempts to use it as an input parameter for the
        /// command, returning true if the vector was successfully used.
        /// </summary>
        /// <param name="input">A 3D vector to be used by the command</param>
        /// <returns>True if the 3D vector was properly used</returns>
        virtual public bool ProcessVector3(Vector3 input) { return false; }

        /// <summary>
        /// Accepts a Splino object and attempts to use it as an input parameter for the
        /// command, returning true if the object was successfully sued.
        /// </summary>
        /// <param name="input">A Splino object to be used by the command</param>
        /// <returns>True if the Splino object was properly used</returns>
        virtual public bool ProcessSplinoObject(SplinoObject input) { return false; }

        /// <summary>
        /// Mouse down event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        virtual public void MouseDown(object sender, MouseEventArgs e) { }

        /// <summary>
        /// Mouse up event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        virtual public void MouseUp(object sender, MouseEventArgs e) { }

        /// <summary>
        /// Mouse enter event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Event arguments</param>
        virtual public void MouseEnter(object sender, EventArgs e)
        {
            CommandManager.Instance.ActiveWindow.Cursor = _activeCursor;
        }

        /// <summary>
        /// Mouse leave event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">EVent arguments</param>
        virtual public void MouseLeave(object sender, EventArgs e) { }

        /// <summary>
        /// Mouse move event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        virtual public void MouseMove(object sender, MouseEventArgs e) { }

        /// <summary>
        /// Mouse wheel event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        virtual public void MouseWheel(object sender, MouseEventArgs e) { }
    }

    /// <summary>
    /// The defauly command sits at the bottom of the active command
    /// stack and is never finalized (popped).  It handles various background
    /// activities such as calculating the world position of the mouse cursor
    /// </summary>
    public class Default : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public Default()
        {
            _name = "Splino Command";
            _usage = "Type a command in the prompt below.  Press F1 for a list of valid commands.";
            _undoable = false;
            _activeCursor = Cursors.Default;
            _commandType = Commands.CommandType.SystemCommand;
        }

        /// <summary>
        /// Executes the command.
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            if (CommandManager.Instance.ActiveCommandStack.Count == 2)
                CommandManager.Instance.ActiveCommandStack.Pop();
        }

        /// <summary>
        /// Finalizes the command.
        /// </summary>
        public override void FinalizeCommand()
        {
            //base.FinalizeCommand();  // The default command should never leave the active command stack
        }

        /// <summary>
        /// Mouse
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public override void MouseMove(object sender, MouseEventArgs e)
        {
            base.MouseMove(sender, e);
            if (CommandManager.Instance.ActiveCommandStack.Peek() != this)
                CommandManager.Instance.ActiveWindow.Command_Default_MouseMove(e);
            else
            {
                if (e.Button == MouseButtons.Left && CommandManager.Instance.ActiveCommandStack.Peek() == this)
                {
                    if (SceneManager.Instance.SelectedObjects.Count > 0)
                    {
                        Move_System move_System = new Move_System();
                        CommandManager.Instance.ExecuteCommand(move_System);
                        move_System.MouseMove(sender, e);
                        move_System.MouseDown(sender, e);
                    }
                }
                else
                    CommandManager.Instance.ActiveWindow.Command_Default_MouseMove(e);
            }
        }

        /// <summary>
        /// Mouse down event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseDown(object sender, MouseEventArgs e)
        {
            base.MouseDown(sender, e);

            SplinoWindow splinoWindow = (SplinoWindow)(((Panel)sender).Tag);

            switch (e.Button)
            {
                case MouseButtons.Left:
                    if (CommandManager.Instance.ActiveCommandStack.Peek() != this)
                        return;
                    CommandManager.Instance.ExecuteCommand(new Select_System());
                    CommandManager.Instance.ActiveCommandStack.Peek().MouseDown(sender, e);
                    break;
                case MouseButtons.Right:
                    switch (splinoWindow.SplinoViewport.CameraType)
                    {
                        case CameraType.Perspective:
                            if (SplinoForm.Instance.KeysShift)
                                CommandManager.Instance.ExecuteCommand(
                                    new Commands.OrthoRightMouseHandler());
                            else
                                CommandManager.Instance.ExecuteCommand(
                                    new Commands.PerspectiveRightMouseHandler());
                            break;
                        default:
                            CommandManager.Instance.ExecuteCommand(
                                    new Commands.OrthoRightMouseHandler());
                            break;
                    }
                    break;
            }
        }
    }

    /// <summary>
    /// Pans the viewport camera.
    /// </summary>
    public class PanCamera : Command
    {
        /// <summary>
        /// The initial camera position vector before execution
        /// </summary>
        protected Vector3 initialCameraPosition;
        /// <summary>
        /// The initial camera target vector before execution
        /// </summary>
        protected Vector3 initialCameraTarget;
        /// <summary>
        /// The final camera position vector after execution
        /// </summary>
        protected Vector3 finalCameraPosition;
        /// <summary>
        /// The final camera position vector after execution
        /// </summary>
        protected Vector3 finalCcameraTarget;

        /// <summary>
        /// Constructor
        /// </summary>
        public PanCamera()
        {
            _name = "PanCamera";
            _description = "Pans a viewport camera.";
            _usage = "Click and drag a viewport to pan.";
            _undoable = true;
            _commandType = Commands.CommandType.ViewportCommand;
            _activeCursor = SplinoForm.Instance.CursorPan;
        }

        /// <summary>
        /// Sets the initial camera vectors
        /// </summary>
        public override void InitializeCommand()
        {
            base.InitializeCommand();
            _activeWindow = CommandManager.Instance.ActiveWindow;
            initialCameraPosition = _activeWindow.SplinoViewport.CameraPosition;
            initialCameraTarget = _activeWindow.SplinoViewport.CameraTarget;
            _objectName = _activeWindow.SplinoViewport.CameraType.ToString();
            _id = _name + ObjectName;
        }

        /// <summary>
        /// Sets the final camera vectors
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            finalCameraPosition = _activeWindow.SplinoViewport.CameraPosition;
            finalCcameraTarget = _activeWindow.SplinoViewport.CameraTarget;
        }

        /// <summary>
        /// Undoes the camera pan
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            _activeWindow.SplinoViewport.CameraPosition = initialCameraPosition;
            _activeWindow.SplinoViewport.CameraTarget = initialCameraTarget;
            _activeWindow.SplinoViewport.UpdateZPlanes();
            _activeWindow.SplinoViewport.UpdateMatrices();
            _activeWindow.SplinoViewport.LayoutAxesOrientationGuide();
        }
        
        /// <summary>
        /// Redoes the camera pan
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            _activeWindow.SplinoViewport.CameraPosition = finalCameraPosition;
            _activeWindow.SplinoViewport.CameraTarget = finalCcameraTarget;
            _activeWindow.SplinoViewport.UpdateZPlanes();
            _activeWindow.SplinoViewport.UpdateMatrices();
            _activeWindow.SplinoViewport.LayoutAxesOrientationGuide();
        }

        /// <summary>
        /// Initializes panning
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseDown(object sender, MouseEventArgs e)
        {
            base.MouseDown(sender, e);
            InitializeCommand();
            _activeWindow.Command_Pan_MouseDown();
        }

        /// <summary>
        /// Mouse enter event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Event arguments</param>
        public override void MouseEnter(object sender, EventArgs e)
        {
            base.MouseEnter(sender, e);
        }

        /// <summary>
        /// Mouse move event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseMove(object sender, MouseEventArgs e)
        {
            base.MouseMove(sender, e);
            if (_initialized)
                _activeWindow.Command_Pan_MouseMove(e);
        }

        /// <summary>
        /// Mouse up event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseUp(object sender, MouseEventArgs e)
        {
            base.MouseUp(sender, e);
            if (_initialized)
                FinalizeCommand();
        }

    }

    /// <summary>
    /// Zooms a viewport's camera
    /// </summary>
    public class ZoomCamera : Command
    {
        /// <summary>
        /// Initial camera position vector before command execution
        /// </summary>
        protected Vector3 initialCameraPosition;
        /// <summary>
        /// Initial camera target position before command execution
        /// </summary>
        protected Vector3 initialCameraTarget;
        /// <summary>
        /// Final camera position vector after command execution
        /// </summary>
        protected Vector3 finalCameraPosition;
        /// <summary>
        /// Final camera target vector after command execution
        /// </summary>
        protected Vector3 finalCameraTarget;
        /// <summary>
        /// Initial viewport width before command execution
        /// </summary>
        protected float initialWidth;
        /// <summary>
        /// Initial viewport height before command execution
        /// </summary>
        protected float initialHeight;
        /// <summary>
        /// Final viewport width after command execution
        /// </summary>
        protected float finalWidth;
        /// <summary>
        /// Final viewport height after command execution
        /// </summary>
        protected float finalHeight;

        /// <summary>
        /// Constructor
        /// </summary>
        public ZoomCamera()
        {
            _name = "ZoomCamera";
            _description = "Zooms a viewport camera.";
            _usage = "Click and drag a viewport to zoom.";
            _undoable = true;
            _commandType = Commands.CommandType.ViewportCommand;
            _activeCursor = SplinoForm.Instance.CursorZoom;
        }

        /// <summary>
        /// Sets the initial camera vectors and viewport dimensions
        /// </summary>
        public override void InitializeCommand()
        {
            base.InitializeCommand();
            _activeWindow = CommandManager.Instance.ActiveWindow;
            initialCameraPosition = _activeWindow.SplinoViewport.CameraPosition;
            initialCameraTarget = _activeWindow.SplinoViewport.CameraTarget;
            initialWidth = _activeWindow.SplinoViewport.Width;
            initialHeight = _activeWindow.SplinoViewport.Height;
            _objectName = _activeWindow.SplinoViewport.CameraType.ToString();
            _id = _name + ObjectName;
        }

        /// <summary>
        /// Sets the final camera vectors and viewport dimensions
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            finalCameraPosition = _activeWindow.SplinoViewport.CameraPosition;
            finalCameraTarget = _activeWindow.SplinoViewport.CameraTarget;
            finalWidth = _activeWindow.SplinoViewport.Width;
            finalHeight = _activeWindow.SplinoViewport.Height;
        }

        /// <summary>
        /// Undoes the zoom
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            _activeWindow.SplinoViewport.CameraPosition = initialCameraPosition;
            _activeWindow.SplinoViewport.CameraTarget = initialCameraTarget;
            _activeWindow.SplinoViewport.Width = initialWidth;
            _activeWindow.SplinoViewport.UpdateZPlanes();
            _activeWindow.SplinoViewport.UpdateMatrices();
            _activeWindow.SplinoViewport.LayoutAxesOrientationGuide();
        }

        /// <summary>
        /// Redoes the zoom
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            _activeWindow.SplinoViewport.CameraPosition = finalCameraPosition;
            _activeWindow.SplinoViewport.CameraTarget = finalCameraTarget;
            _activeWindow.SplinoViewport.Width = finalWidth;
            _activeWindow.SplinoViewport.UpdateZPlanes();
            _activeWindow.SplinoViewport.UpdateMatrices();
            _activeWindow.SplinoViewport.LayoutAxesOrientationGuide();
        }

        /// <summary>
        /// Mouse down event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseDown(object sender, MouseEventArgs e)
        {
            base.MouseDown(sender, e);
            InitializeCommand();
            _activeWindow.Command_Zoo_MouseDown();
        }

        /// <summary>
        /// Mouse enter event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Event arguments</param>
        public override void MouseEnter(object sender, EventArgs e)
        {
            base.MouseEnter(sender, e);
        }

        /// <summary>
        /// Mouse move event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseMove(object sender, MouseEventArgs e)
        {
            base.MouseMove(sender, e);
            if (_initialized)
                _activeWindow.Command_Zoo_MouseMove(e);
        }

        /// <summary>
        /// Mouse up event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseUp(object sender, MouseEventArgs e)
        {
            base.MouseUp(sender, e);
            if (_initialized)
                FinalizeCommand();
        }

    }

    /// <summary>
    /// Handles the mouse event invocation of ZoomCamera
    /// </summary>
    public class ZoomCameraMouse : ZoomCamera
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public ZoomCameraMouse()
        {
            _name = "ZoomCamera";
            _description = "Zooms a viewport camera.";
            _usage = "Roll the mouse wheel to zoom a viewport.";
            _undoable = true;
            _commandType = Commands.CommandType.ViewportCommand;
            _activeWindow = CommandManager.Instance.ActiveWindow;
            _repeatable = true;
            _id = _name + _activeWindow.ToString();
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            CommandManager.Instance.ActiveCommandStack.Push(this);
            InitializeCommand();
        }

        /// <summary>
        /// Mouse wheel event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseWheel(object sender, MouseEventArgs e)
        {
            base.MouseWheel(sender, e);
            _activeWindow.Command_ZoomCameraMouse(e);
            FinalizeCommand();
        }
    }

    /// <summary>
    /// Rotates a viewport's camera
    /// </summary>
    public class RotateCamera : Command
    {
        /// <summary>
        /// The initial camera position vector before command execution
        /// </summary>
        protected Vector3 initialCameraPosition;
        /// <summary>
        /// The initial camera target vector before command execution
        /// </summary>
        protected Vector3 initialCameraTarget;
        /// <summary>
        /// The initial camera up vector before command execution
        /// </summary>
        protected Vector3 initialCameraUpVector;
        /// <summary>
        /// The final camera position vector after command execution
        /// </summary>
        protected Vector3 finalCameraPosition;
        /// <summary>
        /// The final camera target vector after command execution
        /// </summary>
        protected Vector3 finalCameraTarget;
        /// <summary>
        /// The final camera up vector after command execution
        /// </summary>
        protected Vector3 finalCameraUpVector;

        /// <summary>
        /// Constructor
        /// </summary>
        public RotateCamera()
        {
            _name = "RotateCamera";
            _description = "Rotates a viewport camera.";
            _usage = "Click and drag a viewport to rotate.";
            _undoable = true;
            _commandType = Commands.CommandType.ViewportCommand;
            _activeCursor = SplinoForm.Instance.CursorRotate;
        }

        /// <summary>
        /// Sets the initial camera vectors
        /// </summary>
        public override void InitializeCommand()
        {
            base.InitializeCommand();
            _activeWindow = CommandManager.Instance.ActiveWindow;
            initialCameraPosition = _activeWindow.SplinoViewport.CameraPosition;
            initialCameraTarget = _activeWindow.SplinoViewport.CameraTarget;
            initialCameraUpVector = _activeWindow.SplinoViewport.CameraUpVector;
            _objectName = _activeWindow.SplinoViewport.CameraType.ToString();
            _id = _name + ObjectName;
        }

        /// <summary>
        /// Sets the final camera vectors
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            finalCameraPosition = _activeWindow.SplinoViewport.CameraPosition;
            finalCameraTarget = _activeWindow.SplinoViewport.CameraTarget;
            finalCameraUpVector = _activeWindow.SplinoViewport.CameraUpVector;
        }

        /// <summary>
        /// Undoes the camera rotation
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            _activeWindow.SplinoViewport.CameraPosition = initialCameraPosition;
            _activeWindow.SplinoViewport.CameraTarget = initialCameraTarget;
            _activeWindow.SplinoViewport.CameraUpVector = initialCameraUpVector;
            _activeWindow.SplinoViewport.UpdateMatrices();
            _activeWindow.SplinoViewport.LayoutAxesOrientationGuide();
        }

        /// <summary>
        /// Redoes the camera rotation
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            _activeWindow.SplinoViewport.CameraPosition = finalCameraPosition;
            _activeWindow.SplinoViewport.CameraTarget = finalCameraTarget;
            _activeWindow.SplinoViewport.CameraUpVector = finalCameraUpVector;
            _activeWindow.SplinoViewport.UpdateMatrices();
            _activeWindow.SplinoViewport.LayoutAxesOrientationGuide();
        }

        /// <summary>
        /// Mouse down event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseDown(object sender, MouseEventArgs e)
        {
            base.MouseDown(sender, e);
            InitializeCommand();
            _activeWindow.Command_Rotate_MouseDown();
        }

        /// <summary>
        /// Mouse enter event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Event arguments</param>
        public override void MouseEnter(object sender, EventArgs e)
        {
            base.MouseEnter(sender, e);
        }

        /// <summary>
        /// Mouse move event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseMove(object sender, MouseEventArgs e)
        {
            base.MouseMove(sender, e);
            if (_initialized)
                _activeWindow.Command_Rotate_MouseMove(e);
        }

        /// <summary>
        /// Mouse up event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseUp(object sender, MouseEventArgs e)
        {
            base.MouseUp(sender, e);
            if (_initialized)
                FinalizeCommand();
        }

    }

    /// <summary>
    /// Undoes the last view command
    /// </summary>
    public class UndoViewChange : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public UndoViewChange()
        {
            _name = "UndoViewChange";
            _description = "Undoes the last viewport change.";
            _undoable = false;
            _commandType = Commands.CommandType.ViewportCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            CommandManager.Instance.UndoViewCommand();
        }
    }

    /// <summary>
    /// Redoes the last view command that was undone
    /// </summary>
    public class RedoViewChange : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public RedoViewChange()
        {
            _name = "RedoViewChange";
            _description = "Redoes the last viewport change.";
            _undoable = false;
            _commandType = Commands.CommandType.ViewportCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            CommandManager.Instance.RedoViewCommand();
        }
    }

    /// <summary>
    /// Undoes the last object command
    /// </summary>
    public class Undo : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public Undo()
        {
            _name = "Undo";
            _description = "Undoes the last object command.";
            _undoable = false;
            _commandType = Commands.CommandType.ObjectCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            CommandManager.Instance.UndoObjectCommand();
        }
    }

    /// <summary>
    /// Redoes the last object command that was undone
    /// </summary>
    public class Redo : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public Redo()
        {
            _name = "Redo";
            _description = "Redoes the last object command.";
            _undoable = false;
            _commandType = CommandType.ObjectCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            CommandManager.Instance.RedoObjectCommand();
        }
    }

    /// <summary>
    /// Launches the Undo Multiple form, enabling the user to select
    /// multiple object commands to undo
    /// </summary>
    public class UndoMultiple : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public UndoMultiple()
        {
            _name = "UndoMultiple";
            _description = "Undoes multiple commands.";
            _undoable = false;
            _commandType = CommandType.ObjectCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            CommandManager.Instance.UndoMultiple();
        }
    }

    /// <summary>
    /// Launches the Redo Multiple form, allowing the user
    /// to redo multiple object commands that were undone.
    /// </summary>
    public class RedoMultiple : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public RedoMultiple()
        {
            _name = "RedoMultiple";
            _description = "Redoes multiple commands.";
            _undoable = false;
            _commandType = CommandType.ObjectCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            CommandManager.Instance.RedoMultiple();
        }
    }

    /// <summary>
    /// Base class for commands that involve drawing.
    /// </summary>
    public class Draw : Command
    {
        private Vector3 _basePoint = new Vector3(0f,0f,0f);
        /// <summary>
        /// Gets or sets the vector representing the base point for calculating
        /// distance between the cursor
        /// </summary>
        protected Vector3 BasePoint
        {
            get { return _basePoint; }
            set
            {
                _basePoint = value;
                UpdateDistance();
                SceneManager.Instance.BaseDrawPoint = value;
                SceneManager.Instance.BaseDrawPointInitialized = true;
                foreach (SplinoViewport splinoViewport in DeviceManager.Instance.Viewports)
                    splinoViewport.ComputeAngleSnapPoints();
            }
        }

        /// <summary>
        /// Constructor
        /// </summary>
        protected Draw()
        {
            _activeWindow = CommandManager.Instance.ActiveWindow;
            _activeCursor = SplinoForm.Instance.CursorDraw;
        }

        /// <summary>
        /// Computes the distance between the cursor draw point and the base draw point.
        /// </summary>
        /// <returns>The distance between the cursor draw point and the base draw point.</returns>
        private void UpdateDistance()
        {
            
            float distance = ((Vector3)(_basePoint - SceneManager.Instance.CursorPoint)).Length();
            SplinoForm.Instance.LabelDistance.Text =
                String.Format("Distance {0:0.000}", distance);
        }

        /// <summary>
        /// Initializes the command, and makes the Distance status bar label visible.
        /// </summary>
        public override void InitializeCommand()
        {
            base.InitializeCommand();

            UpdateDistance();
            SplinoForm.Instance.LabelDistance.Visible = true;
        }

        /// <summary>
        /// Finalizes the command, and makes the Distance status bar label invisible.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            SplinoForm.Instance.LabelDistance.Visible = false;
            SceneManager.Instance.BaseDrawPointInitialized = false;
            CommandManager.Instance.ActiveWindow.SnapLabel.Hide();
        }

        /// <summary>
        /// Mouse enter event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Event arguments</param>
        public override void MouseEnter(object sender, EventArgs e)
        {
            base.MouseEnter(sender, e);
            _pointCursorActive = true;
        }


        /// <summary>
        /// Mouse leave event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">EVent arguments</param>
        public override void MouseLeave(object sender, EventArgs e)
        {
            base.MouseLeave(sender, e);
            _pointCursorActive = false;
        }

        /// <summary>
        /// Mouse move event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseMove(object sender, MouseEventArgs e)
        {
            base.MouseMove(sender, e);
            _activeWindow.Command_Draw_MouseMove(e);
            UpdateDistance();
        }

        /// <summary>
        /// Mouse down event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseDown(object sender, MouseEventArgs e)
        {
            base.MouseDown(sender, e);
            CommandManager.Instance.ActiveWindow.SnapLabel.Hide();
        }
    }

    /// <summary>
    /// Creates a point object and adds it to the scene
    /// </summary>
    public class Point : Draw
    {
        /// <summary>
        /// The newly created point
        /// </summary>
        PointObject _newPoint;

        /// <summary>
        /// Constructor
        /// </summary>
        public Point() : base()
        {
            _name = "Point";
            _description = "Creates a point object.";
            _usage = "Click on a viewport, or enter the point's location below: \"x,y,z\"";
            _undoable = true;
            _commandType = Commands.CommandType.ObjectCommand;
            _processingInput = true;
        }

        /// <summary>
        /// Initializes the new point, adding it to the scene, and
        /// outputs its location to the command prompt
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (_finalizable)
            {
                _newPoint.Initialize(SceneManager.Instance.MasterSceneObject);
                _pointCursorActive = false;
                if (_newPoint != null)
                    CommandManager.Instance.WriteOutputLine("\"" +
                        _newPoint.Name + "\" created at " +
                        _newPoint.Center.X + ", " +
                        _newPoint.Center.Y + ", " +
                        _newPoint.Center.Z);
            }
        }

        /// <summary>
        /// Deletes the point created by this command
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            _newPoint.Delete();
        }
        
        /// <summary>
        /// Undeletes the point created by this command
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            _newPoint.Undelete();
        }

        /// <summary>
        /// Creates a new point object at the location of the 
        /// the cursor draw point
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseDown(object sender, MouseEventArgs e)
        {
            base.MouseDown(sender, e);
            _newPoint = SceneManager.Instance.Command_Point_MouseDown();
            InitializeCommand();
            _finalizable = true;
            FinalizeCommand();
        }

        /// <summary>
        /// Accepts an object of varying type for the location
        /// of the new point object.
        /// </summary>
        /// <param name="input">A float representing the origin,
        /// a vecto2 representing grid coorindates, or
        /// a vector3 representing world coorindates for the new point</param>
        /// <param name="inputs">An array of objects of varying type that will be
        /// cast and used by the command</param>
        /// <returns>True if the input object was used properly</returns>
        public override bool ProcessInput(object input, object[] inputs)
        {
            bool returnVal = false;
            switch (input.GetType().Name)
            {
                case "Single":
                    float inputFloat = (float)input;
                    if (inputFloat == 0f)
                        _newPoint = SceneManager.Instance.Command_Point_Input(
                            new Vector3(0f, 0f, 0f));
                    InitializeCommand();
                    _finalizable = true;
                    FinalizeCommand();
                    returnVal = true;
                    break;
                case "Vector2":
                    Vector2 inputVector2 = (Vector2)input;
                    Vector3 pointCenter = CommandManager.Instance.ActiveWindow.SplinoViewport.
                        GridToWorld(inputVector2);
                    _newPoint = SceneManager.Instance.Command_Point_Input(pointCenter);
                    InitializeCommand();
                    _finalizable = true;
                    FinalizeCommand();
                    returnVal = true;
                    break;
                case "Vector3":
                    Vector3 inputVector3 = (Vector3)input;
                    _newPoint = SceneManager.Instance.Command_Point_Input(inputVector3);
                    InitializeCommand();
                    _finalizable = true;
                    FinalizeCommand();
                    returnVal = true;
                    break;
            }
            return returnVal;
        }
    }

    /// <summary>
    /// Handles all right mouse clicks, which either cancel
    /// an active command or repeat the last command
    /// </summary>
    public class RightMouseHandler : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public RightMouseHandler()
        {
            _commandType = CommandType.SystemCommand;
        }

        /// <summary>
        /// Mouse up event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseUp(object sender, MouseEventArgs e)
        {
            base.MouseUp(sender, e);
            FinalizeCommand();
            if (CommandManager.Instance.ActiveCommandStack.Count == 1 &&
                CommandManager.Instance.LastCommand != null)
            {
                CommandManager.Instance.ExecuteCommand(CommandManager.Instance.LastCommand);
            }
            else
                CommandManager.Instance.ActiveCommandStack.Peek().FinalizeCommand();
        }
    }

    /// <summary>
    /// Handles mouse movement in orthographic viewports
    /// </summary>
    public class OrthoRightMouseHandler : RightMouseHandler
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public OrthoRightMouseHandler()
        {
            _activeWindow = CommandManager.Instance.ActiveWindow;
            _commandType = CommandType.SystemCommand;
        }

        /// <summary>
        /// Mouse move event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseMove(object sender, MouseEventArgs e)
        {
            base.MouseMove(sender, e);

            FinalizeCommand();
            CommandManager.Instance.ExecuteCommand(new Commands.PanCamera());
            CommandManager.Instance.ActiveCommandStack.Peek().MouseDown(null, e);
            CommandManager.Instance.ActiveCommandStack.Peek().MouseEnter(null, e);
            CommandManager.Instance.ActiveCommandStack.Peek().MouseMove(null, e);
        }
    }

    /// <summary>
    /// Handles mouse movement in the perspective viewport
    /// </summary>
    public class PerspectiveRightMouseHandler : RightMouseHandler
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public PerspectiveRightMouseHandler()
        {
            _activeWindow = CommandManager.Instance.ActiveWindow;
            _commandType = CommandType.SystemCommand;
        }

        /// <summary>
        /// Mouse move event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseMove(object sender, MouseEventArgs e)
        {
            base.MouseMove(sender, e);

            FinalizeCommand();
            CommandManager.Instance.ExecuteCommand(new Commands.RotateCamera());
            CommandManager.Instance.ActiveCommandStack.Peek().MouseDown(null, e);
            CommandManager.Instance.ActiveCommandStack.Peek().MouseEnter(null, e);
            CommandManager.Instance.ActiveCommandStack.Peek().MouseMove(null, e);
        }
    }

    /// <summary>
    /// Saves the scene and viewport layout to file
    /// </summary>
    public class Save : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public Save()
        {
            this._name = "Save";
            this._description = "Saves the current scene to file.";
            this._undoable = false;
            this._commandType = CommandType.ObjectCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            SplinoForm.Instance.SaveFile();
        }
    }

    /// <summary>
    /// Saves the scene and viewport layout to a new file name
    /// </summary>
    public class SaveAs : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public SaveAs()
        {
            this._name = "SaveAs";
            this._description = "Saves the current scene to a new file.";
            this._undoable = false;
            this._commandType = CommandType.ObjectCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            SplinoForm.Instance.SaveFileAs();
        }
    }

    /// <summary>
    /// Clears the scene and viewport layout to start a new file
    /// </summary>
    public class New : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public New()
        {
            this._name = "New";
            this._description = "Creates a new Splino scene.";
            this._undoable = false;
            this._commandType = CommandType.ObjectCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            SplinoForm.Instance.NewFile();
        }
    }

    /// <summary>
    /// Opens a splino.xml file
    /// </summary>
    public class Open : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public Open()
        {
            this._name = "Open";
            this._description = "Opens an existing Splino file.";
            this._undoable = false;
            this._commandType = CommandType.ObjectCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            SplinoForm.Instance.OpenFile();
        }
    }

    /// <summary>
    /// Shuts down the Splino application
    /// </summary>
    public class Exit : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public Exit()
        {
            this._name = "Exit";
            this._description = "Exits Splino.";
            this._undoable = false;
            this._commandType = CommandType.ObjectCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            SplinoForm.Instance.Exit();
        }
    }

    /// <summary>
    /// Prompts the user for Splino Objects to change to the selected state
    /// </summary>
    public class Select : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public Select()
        {
            this._name = "Select";
            this._description = "Selects a Splino object.";
            this._undoable = false;
            this._commandType = CommandType.ObjectCommand;
            this._usage = "Click on an object or enter object names: \"Object1\",\"Object2\"";
            this._processingInput = true;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="inputObjects">Splino Objects to select</param>
        public Select(SplinoObject[] inputObjects) : this()
        {
            _inputObjects = inputObjects;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            if (_inputObjects != null)
            {
                foreach (SplinoObject splinoObject in _inputObjects)
                    splinoObject.Select();
                FinalizeCommand();
            }
        }

        /// <summary>
        /// Mouse down event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseDown(object sender, MouseEventArgs e)
        {
            base.MouseDown(sender, e);

            List<SplinoObject> intersectedObjects;

            if (CommandManager.Instance.ActiveWindow.SplinoViewport.CameraType == CameraType.Perspective)
                intersectedObjects = SceneManager.Instance.MasterSceneObject.IntersectRay(
                    CommandManager.Instance.ActiveWindow.SplinoViewport,
                    CommandManager.Instance.ActiveWindow.SplinoViewport.CameraPosition,
                    Vector3.Subtract(
                    CommandManager.Instance.ActiveWindow.SplinoViewport.ScreenToTargetPlane(e.X, e.Y),
                    CommandManager.Instance.ActiveWindow.SplinoViewport.CameraPosition));
            else
                intersectedObjects = SceneManager.Instance.MasterSceneObject.IntersectRay(
                    CommandManager.Instance.ActiveWindow.SplinoViewport,
                    CommandManager.Instance.ActiveWindow.SplinoViewport.ScreenToCameraNearPlane(e.X, e.Y),
                    Vector3.Subtract(
                    CommandManager.Instance.ActiveWindow.SplinoViewport.ScreenToTargetPlane(e.X, e.Y),
                    CommandManager.Instance.ActiveWindow.SplinoViewport.ScreenToCameraNearPlane(e.X, e.Y)));
            List<SplinoObject> unlockedObjects = new List<SplinoObject>();
            foreach (SplinoObject splinoObject in intersectedObjects)
                if (!splinoObject.Locked)
                    unlockedObjects.Add(splinoObject);
            switch (unlockedObjects.Count)
            {
                case 0: // No objects were hit
                    SceneManager.Instance.ClearSelectedItems();
                    DeviceManager.Instance.SelectionRectangleViewPort =
                        CommandManager.Instance.ActiveWindow.SplinoViewport.CameraType;
                    SceneManager.Instance.SelectionStartPoint =
                        new Vector2(e.X, e.Y);
                    SceneManager.Instance.SelectionEndPoint =
                        new Vector2(e.X, e.Y);
                    DeviceManager.Instance.DrawSelectionRectangle = true;
                    break;
                case 1: // One object was hit
                    SceneManager.Instance.ClearSelectedItems();
                    SceneManager.Instance.SelectedObjects.Add(intersectedObjects[0]);
                    unlockedObjects[0].Select();
                    FinalizeCommand();
                    break;
                default: // Multiple objects were hit
                    SceneManager.Instance.ClearSelectedItems();
                    SceneManager.Instance.SelectedObjects.AddRange(unlockedObjects);
                    SingleSelectionForm singleSelectionForm =
                        new SingleSelectionForm();
                    singleSelectionForm.Show(SplinoForm.Instance);
                    break;
            }
        }

        /// <summary>
        /// Mouse up event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseUp(object sender, MouseEventArgs e)
        {
            base.MouseUp(sender, e);
            if (SceneManager.Instance.SelectionStartPoint !=
                SceneManager.Instance.SelectionEndPoint)
            {
                if (SceneManager.Instance.SelectionStartPoint.X <
                    SceneManager.Instance.SelectionEndPoint.X)
                    CommandManager.Instance.ExecuteCommand(new Commands.SelectInclusive_System());
                else
                    CommandManager.Instance.ExecuteCommand(new Commands.SelectExclusive_System());
            }
            DeviceManager.Instance.DrawSelectionRectangle = false;
            DeviceManager.Instance.RequestRender();
            FinalizeCommand();
        }

        /// <summary>
        /// Mouse move event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseMove(object sender, MouseEventArgs e)
        {
            base.MouseMove(sender, e);
            if (DeviceManager.Instance.DrawSelectionRectangle)
            {
                SceneManager.Instance.SelectionEndPoint =
                    new Vector2(e.X, e.Y);
                DeviceManager.Instance.RequestRender();
            }
        }

        /// <summary>
        /// Takes a List of type SplinoObject and puts each Splino Object
        /// in the list into a selected state
        /// </summary>
        /// <param name="input">List of type SplinoObject</param>
        /// <param name="inputs">An array of objects of varying type that will be
        /// cast and used by the command</param>
        /// <returns>True if the input object was used properly</returns>
        public override bool ProcessInput(object input, object[] inputs)
        {
            bool returnVal = false;
            switch (input.GetType().Name)
            {
                case "List`1":
                    List<SplinoObject> splinoObjects = (List<SplinoObject>)input;
                    foreach (SplinoObject splinoObject in splinoObjects)
                        splinoObject.Select();
                    FinalizeCommand();
                    break;
            }
            return returnVal;
        }

        /// <summary>
        /// Outputs which objects were selected
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (_inputObjects == null)
            {
                if (SceneManager.Instance.SelectedObjects.Count > 1)
                    CommandManager.Instance.WriteOutputLine(
                        SceneManager.Instance.SelectedObjects.Count +
                        " objects selected.");
                else if (SceneManager.Instance.SelectedObjects.Count == 1)
                    CommandManager.Instance.WriteOutputLine("\"" +
                        SceneManager.Instance.SelectedObjects[0].Name +
                        "\" object selected.");
            }
            else
            {
                if (_inputObjects.Length > 1)
                    CommandManager.Instance.WriteOutputLine(
                        _inputObjects.Length + " objects selected.");
                else if (_inputObjects.Length == 1)
                    CommandManager.Instance.WriteOutputLine("\"" +
                        _inputObjects[0].Name + "\" object selected.");
            }
        }
    }

    /// <summary>
    /// Selects all Splino Objects in the scene that are not
    /// hidden or locked
    /// </summary>
    public class SelectAll : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public SelectAll()
        {
            this._name = "SelectAll";
            this._description = "Selects all Splino objects in the scene.";
            this._undoable = false;
            this._commandType = CommandType.ObjectCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            foreach (SplinoObject splinoObject in
                SceneManager.Instance.MasterSceneObject.SceneChildren)
                splinoObject.Select();
        }
    }

    /// <summary>
    /// Deselects all Splino Objects in the scene that are currently selected
    /// </summary>
    public class SelectNone : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public SelectNone()
        {
            this._name = "SelectNone";
            this._description = "Deselects all Splino objects.";
            this._undoable = false;
            this._commandType = CommandType.ObjectCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            SceneManager.Instance.ClearSelectedItems();
        }
    }

    /// <summary>
    /// Selects all objects that are at least partly inside the selection rectangle
    /// </summary>
    public class SelectInclusive : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public SelectInclusive()
        {
            this._name = "SelectInclusive";
            this._description = "Selects all objects that are at least partly inside the selection rectangle.";
            this._undoable = false;
            this._commandType = CommandType.ObjectCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();

            List<SplinoObject> splinoObjects =
                SceneManager.Instance.MasterSceneObject.IntersectInclusive(
                    CommandManager.Instance.ActiveWindow.SplinoViewport);

            foreach (SplinoObject splinoObject in splinoObjects)
                if (!splinoObject.Locked)
                    splinoObject.Select();

            FinalizeCommand();
        }
    }

    /// <summary>
    /// Selects only objects that are completely within the selection rectangle
    /// </summary>
    public class SelectExclusive : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public SelectExclusive()
        {
            this._name = "SelectExclusive";
            this._description = "Selects only objects that are completely within the selection rectangle.";
            this._undoable = false;
            this._commandType = CommandType.ObjectCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();

            List<SplinoObject> splinoObjects = 
            SceneManager.Instance.MasterSceneObject.IntersectExclusive(
                CommandManager.Instance.ActiveWindow.SplinoViewport);

            foreach (SplinoObject splinoObject in splinoObjects)
                if (!splinoObject.Locked)
                    splinoObject.Select();

            FinalizeCommand();
        }

    }

    /// <summary>
    /// Handles mouse click selection of Splino Objects so that
    /// each click on a viewport doesn't output to the Command Prompt
    /// </summary>
    public class Select_System : Select
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public Select_System()
        {
            this._name = "Select";
            this._description = "Selects a Splino object.";
            this._undoable = false;
            this._commandType = CommandType.SystemCommand;
            this._processingInput = false;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="inputObjects">Splino Objects to select</param>
        public Select_System(SplinoObject[] inputObjects) : base(inputObjects) 
        {
            _commandType = CommandType.SystemCommand;
            _processingInput = false;
        }
    }

    /// <summary>
    /// Selects all objects that are at least partly inside the selection rectangle,
    /// without outputting each rectangle draw to the Command Prompt
    /// </summary>
    public class SelectInclusive_System : SelectInclusive
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public SelectInclusive_System()
        {
            this._name = "SelectInclusive";
            this._description = "Selects all objects that are at least partly inside the selection rectangle.";
            this._undoable = false;
            this._commandType = CommandType.SystemCommand;
        }

    }

    /// <summary>
    /// Selects only objects that are completely within the selection rectangle, without
    /// outputting each rectangle draw to the Command Prompt
    /// </summary>
    public class SelectExclusive_System : SelectExclusive
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public SelectExclusive_System()
        {
            this._name = "SelectExclusive";
            this._description = "Selects only objects that are completely within the selection rectangle.";
            this._undoable = false;
            this._commandType = CommandType.SystemCommand;
        }
    }

    /// <summary>
    /// Deselects all selected Splino Objects, and selects all unselected Splino 
    /// Objects if they are not hidden or locked
    /// </summary>
    public class InvertSelection : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public InvertSelection()
        {
            this._name = "InvertSelection";
            this._description = "Selects all unselected objects, and deselects all selected objects.";
            this._undoable = false;
            this._commandType = CommandType.ObjectCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            SceneManager.Instance.InvertSelection();
        }
    }

    /// <summary>
    /// Deletes selected Splino Objects from the scene
    /// </summary>
    public class Delete : Command
    {
        /// <summary>
        /// A list of the Splino Objects that were deleted
        /// </summary>
        List<SplinoObject> _deletedObjects = new List<SplinoObject>();

        /// <summary>
        /// Constructor
        /// </summary>
        public Delete()
        {
            this._name = "Delete";
            this._description = "Deletes a Splino object.";
            this._undoable = true;
            this._commandType = CommandType.ObjectCommand;
        }

        /// <summary>
        /// Deletes all selected Splino Objects
        /// </summary>
        public override void Execute()
        {
            if (SceneManager.Instance.SelectedObjects.Count > 0)
            {
                base.Execute();

                foreach (SplinoObject splinoObject in
                    SceneManager.Instance.SelectedObjects)
                {
                    _deletedObjects.Add(splinoObject);
                }
                foreach (SplinoObject splinoObject in _deletedObjects)
                    splinoObject.Delete();

                _finalizable = true;
                FinalizeCommand();

                if (_deletedObjects.Count > 1)
                    CommandManager.Instance.WriteOutputLine(
                        _deletedObjects.Count.ToString() + " objects deleted.");
                else
                    CommandManager.Instance.WriteOutputLine("\"" + _deletedObjects[0].Name +
                         "\" deleted.");
            }
        }

        /// <summary>
        /// Undeletes each object in the _deletedObjects member
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            foreach (SplinoObject splinoObject in _deletedObjects)
                splinoObject.Undelete();
        }

        /// <summary>
        /// Deletes each object in the _deletedObjects member
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            foreach (SplinoObject splinoObject in _deletedObjects)
                splinoObject.Delete();
        }
    }

    /// <summary>
    /// Copies currently selected Splino Objects to the clipboard
    /// </summary>
    public class CopyClipboard : Command
    {
        /// <summary>
        /// A Splino Object whose scene children are the
        /// Splino Objects copied to the clipboard
        /// </summary>
        SplinoObject _clipboardObject;

        /// <summary>
        /// Constructor
        /// </summary>
        public CopyClipboard()
        {
            _name = "CopyClipboard";
            _description = "Copies currently selected Splino objects to the clipboard.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Copies the selected objects to the clipboard
        /// </summary>
        public override void Execute()
        {
            base.Execute();

            if (SceneManager.Instance.SelectedObjects.Count > 0)
            {
                _clipboardObject = new SplinoObject();
                foreach (SplinoObject splinoObject in
                    SceneManager.Instance.SelectedObjects)
                    _clipboardObject.SceneChildren.Add(splinoObject);
                IDataObject dataObject = new DataObject();
                dataObject.SetData(typeof(SplinoObject), _clipboardObject);
                Clipboard.SetDataObject(dataObject, true);

                SplinoForm.Instance.PasteMenuItem.Enabled = true;
            }

            FinalizeCommand();
        }

        /// <summary>
        /// Outputs the Splino Objects that were copied to the clipboard
        /// </summary>
        public override void FinalizeCommand()
        {
            if (_clipboardObject.SceneChildren.Count > 0)
            {
                base.FinalizeCommand();
                if (_clipboardObject.SceneChildren.Count > 1)
                    CommandManager.Instance.WriteOutputLine(_clipboardObject.SceneChildren.Count.ToString() +
                        " objects copied to the clipboard.");
                else
                {
                    CommandManager.Instance.WriteOutputLine("\"" + _clipboardObject.SceneChildren[0].Name +
                        "\" copied to the clipboard.");
                }
            }
        }
    }

    /// <summary>
    /// Pastes the Splino Objects contained in the clipboard, if the clipboard contains 
    /// a data object of type SplinoObject
    /// </summary>
    public class PasteClipboard : Command
    {
        /// <summary>
        /// The Splino Object whose children are pasted form the clipboard
        /// </summary>
        SplinoObject _clipboardObject;

        /// <summary>
        /// Constructor
        /// </summary>
        public PasteClipboard()
        {
            this._name = "PasteClipboard";
            this._description = "Pastes Splino objects from the clipboard into the scene.";
            this._undoable = true;
            this._commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Pastes the Splino Objects in the clipboard into the scene
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            IDataObject dataObject = Clipboard.GetDataObject();

            if (dataObject.GetDataPresent(typeof(SplinoObject)))
            {
                SceneManager.Instance.ClearSelectedItems();
                _clipboardObject = (SplinoObject)dataObject.GetData(SplinoObject.Format);
                foreach (SplinoObject splinoObject in _clipboardObject.SceneChildren)
                {
                    splinoObject.ResetBuffers();
                    splinoObject.Initialize(
                        SceneManager.Instance.GetSplinoObjectByName(splinoObject.SceneParentName));
                    splinoObject.Select();
                }
            }

            _finalizable = true;
            FinalizeCommand();
        }

        /// <summary>
        /// Outputs which Splino Objects were pasted from the clipboard
        /// </summary>
        public override void FinalizeCommand()
        {
            if (_clipboardObject != null && _clipboardObject.SceneChildren.Count > 0)
            {
                base.FinalizeCommand();
                if (_clipboardObject.SceneChildren.Count > 1)
                    CommandManager.Instance.WriteOutputLine(_clipboardObject.SceneChildren.Count.ToString() +
                        " objects pasted from the clipboard.");
                else
                {
                    CommandManager.Instance.WriteOutputLine("\"" + _clipboardObject.SceneChildren[0].Name +
                        "\" pasted from the clipboard.");
                }
            }
            else
                CommandManager.Instance.WriteOutputLine("No Splino Objects in the clipboard.");
        }

        /// <summary>
        /// Deletes the objects that were pasted from the clipboard
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            foreach (SplinoObject splinoObject in _clipboardObject.SceneChildren)
                splinoObject.Delete();
        }

        /// <summary>
        /// Undeletes the objects that were pasted from the clipboard
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            foreach (SplinoObject splinoObject in _clipboardObject.SceneChildren)
                splinoObject.Undelete();
        }
    }

    /// <summary>
    /// Copies Splino Objects to the clipboard and deletes them from the scene
    /// </summary>
    public class CutClipboard : Command
    {
        /// <summary>
        /// The Splino Objects that were copied to the clipboard and deleted
        /// </summary>
        SplinoObject _clipboardObject;
        List<SplinoObject> _deletedObjects = new List<SplinoObject>();

        /// <summary>
        /// Constructor
        /// </summary>
        public CutClipboard()
        {
            this._name = "CutClipboard";
            this._description = "Copies splino objects to the clipboard and deletes them from the scene.";
            this._undoable = true;
            this._commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Copies the selected Splino Objects to the clipboard and deletes them form the scene
        /// </summary>
        public override void Execute()
        {
            base.Execute();

            if (SceneManager.Instance.SelectedObjects.Count > 0)
            {
                _clipboardObject = new SplinoObject();
                foreach (SplinoObject splinoObject in
                    SceneManager.Instance.SelectedObjects)
                {
                    _clipboardObject.SceneChildren.Add(splinoObject);
                    _deletedObjects.Add(splinoObject);
                }
                IDataObject dataObject = new DataObject();
                dataObject.SetData(typeof(SplinoObject), _clipboardObject);
                Clipboard.SetDataObject(dataObject, true);

                SplinoForm.Instance.PasteMenuItem.Enabled = true;
            }

            foreach (SplinoObject splinoObject in _deletedObjects)
            {
                splinoObject.Deselect();
                splinoObject.Delete();
            }

            _finalizable = true;
            FinalizeCommand();
        }

        /// <summary>
        /// Outputs which Splino Objects were copied to the clipboard and deleted form the scene
        /// </summary>
        public override void FinalizeCommand()
        {
            if (_clipboardObject != null && _clipboardObject.SceneChildren.Count > 0)
            {
                base.FinalizeCommand();
                if (_clipboardObject.SceneChildren.Count > 1)
                    CommandManager.Instance.WriteOutputLine(_clipboardObject.SceneChildren.Count.ToString() +
                        " objects cut and copied to the clipboard.");
                else
                {
                    CommandManager.Instance.WriteOutputLine("\"" + _clipboardObject.SceneChildren[0].Name +
                        "\" cut and copied to the clipboard.");
                }
            }
        }

        /// <summary>
        /// Undeletes the Splino Objects that were deleted from the scene
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            foreach (SplinoObject splinoObject in _deletedObjects)
                splinoObject.Undelete();
        }

        /// <summary>
        /// Deletes the Splino Objects that were deleted from the scene,
        /// but does not recopy them to the clipboard.  This may change in future versions.
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            foreach (SplinoObject splinoObject in _deletedObjects)
                splinoObject.Delete();
        }
    }

    /// <summary>
    /// Toggles drawing point grid snapping on and off
    /// </summary>
    public class GridSnap : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public GridSnap()
        {
            _name = "GridSnap";
            _description = "Toggles snapping of drawing point to viewport grid.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            SplinoForm.Instance.Command_GridSnap();
            FinalizeCommand();
        }

        /// <summary>
        /// Outputs whether grid snapping is on or off
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (SplinoForm.Instance.GridSnapSelected)
                CommandManager.Instance.WriteOutputLine("Grid snapping on.");
            else
                CommandManager.Instance.WriteOutputLine("Grid snapping off");
        }
    }

    /// <summary>
    /// Toggles drawing point angle snapping on and off
    /// </summary>
    public class AngleSnap : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public AngleSnap()
        {
            _name = "AngleSnap";
            _description = "Toggles snapping of drawing point to angle.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            SplinoForm.Instance.Command_AngleSnap();
            FinalizeCommand();
        }

        /// <summary>
        /// Outputs whether angle snapping is on or off.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (SplinoForm.Instance.AngleSnapSelected)
                CommandManager.Instance.WriteOutputLine("Angle snapping on.");
            else
                CommandManager.Instance.WriteOutputLine("Angle snapping off");
        }
    }

    /// <summary>
    /// Toggles drawing object snapping on and off
    /// </summary>
    public class ObjectSnap : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public ObjectSnap()
        {
            _name = "ObjectSnap";
            _description = "Toggles snapping of drawing point to part of object.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            SplinoForm.Instance.Command_ObjectSnap();
            FinalizeCommand();
        }

        /// <summary>
        /// Outputs whether angle snapping is on or off.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (SplinoForm.Instance.ObjectSnapSelected)
                CommandManager.Instance.WriteOutputLine("Object snapping on.");
            else
                CommandManager.Instance.WriteOutputLine("Object snapping off");
        }
    }

    /// <summary>
    /// Toggles object endpoint snapping on and off
    /// </summary>
    public class ObjectEndSnap : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public ObjectEndSnap()
        {
            _name = "ObjectEndSnap";
            _description = "Toggles snapping of drawing point to object endpoints.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            SplinoForm.Instance.Command_ObjectEndSnap();
            FinalizeCommand();
        }

        /// <summary>
        /// Outputs whether object endpoint snapping is on or off.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (SplinoForm.Instance.ObjectEndSnapSelected)
                CommandManager.Instance.WriteOutputLine("Object endpoint snapping on.");
            else
                CommandManager.Instance.WriteOutputLine("Object endpoint snapping off");
        }
    }

    /// <summary>
    /// Toggles near to object snapping on and off
    /// </summary>
    public class ObjectNearSnap : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public ObjectNearSnap()
        {
            _name = "ObjectNearSnap";
            _description = "Toggles snapping of drawing point to near objects.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            SplinoForm.Instance.Command_ObjectNearSnap();
            FinalizeCommand();
        }

        /// <summary>
        /// Outputs whether near to object snapping is on or off.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (SplinoForm.Instance.ObjectNearSnapSelected)
                CommandManager.Instance.WriteOutputLine("Near to object snapping on.");
            else
                CommandManager.Instance.WriteOutputLine("Near to object snapping off");
        }
    }

    /// <summary>
    /// Toggles point object snapping on and off
    /// </summary>
    public class ObjectPointSnap : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public ObjectPointSnap()
        {
            _name = "ObjectPointSnap";
            _description = "Toggles snapping of drawing point to point objects.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            SplinoForm.Instance.Command_ObjectPointSnap();
            FinalizeCommand();
        }

        /// <summary>
        /// Outputs whether point object snapping is on or off.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (SplinoForm.Instance.ObjectPointSnapSelected)
                CommandManager.Instance.WriteOutputLine("Point object snapping on.");
            else
                CommandManager.Instance.WriteOutputLine("Point object snapping off");
        }
    }

    /// <summary>
    /// Toggles object midpoint snapping on and off
    /// </summary>
    public class ObjectMidSnap : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public ObjectMidSnap()
        {
            _name = "ObjectMidSnap";
            _description = "Toggles snapping of drawing point to object midpoints.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            SplinoForm.Instance.Command_ObjectMidSnap();
            FinalizeCommand();
        }

        /// <summary>
        /// Outputs whether object midpoint snapping is on or off.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (SplinoForm.Instance.ObjectMidSnapSelected)
                CommandManager.Instance.WriteOutputLine("Object midpoint snapping on.");
            else
                CommandManager.Instance.WriteOutputLine("Object midpoint snapping off");
        }
    }

    /// <summary>
    /// Toggles object center snapping on and off
    /// </summary>
    public class ObjectCenterSnap : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public ObjectCenterSnap()
        {
            _name = "ObjectCenterSnap";
            _description = "Toggles snapping of drawing point to object centers.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            SplinoForm.Instance.Command_ObjectCenterSnap();
            FinalizeCommand();
        }

        /// <summary>
        /// Outputs whether object center snapping is on or off.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (SplinoForm.Instance.ObjectCenterSnapSelected)
                CommandManager.Instance.WriteOutputLine("Object center snapping on.");
            else
                CommandManager.Instance.WriteOutputLine("Object center snapping off");
        }
    }

    /// <summary>
    /// Toggles object intersection snapping on and off
    /// </summary>
    public class ObjectIntersectSnap : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public ObjectIntersectSnap()
        {
            _name = "ObjectIntersectSnap";
            _description = "Toggles snapping of drawing point to intersecting objects.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            SplinoForm.Instance.Command_ObjectIntersectSnap();
            FinalizeCommand();
        }

        /// <summary>
        /// Outputs whether point object snapping is on or off.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (SplinoForm.Instance.ObjectIntersectSnapSelected)
                CommandManager.Instance.WriteOutputLine("Intersecting object snapping on.");
            else
                CommandManager.Instance.WriteOutputLine("Intersecting object snapping off");
        }
    }

    /// <summary>
    /// Toggles perpendicular to object snapping on and off
    /// </summary>
    public class ObjectPerpSnap : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public ObjectPerpSnap()
        {
            _name = "ObjectPerpSnap";
            _description = "Toggles snapping of drawing line to perpendicular points.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            SplinoForm.Instance.Command_ObjectPerpSnap();
            FinalizeCommand();
        }

        /// <summary>
        /// Outputs whether perpendicular to object snapping is on or off.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (SplinoForm.Instance.ObjectPerpSnapSelected)
                CommandManager.Instance.WriteOutputLine("Perpendicular to object snapping on.");
            else
                CommandManager.Instance.WriteOutputLine("Perpendicular to object snapping off");
        }
    }

    /// <summary>
    /// Toggles tangent to object snapping on and off
    /// </summary>
    public class ObjectTanSnap : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public ObjectTanSnap()
        {
            _name = "ObjectTanSnap";
            _description = "Toggles snapping of drawing line to tangent points.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            SplinoForm.Instance.Command_ObjectTanSnap();
            FinalizeCommand();
        }

        /// <summary>
        /// Outputs whether tangent to object snapping is on or off.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (SplinoForm.Instance.ObjectTanSnapSelected)
                CommandManager.Instance.WriteOutputLine("Tangent to object snapping on.");
            else
                CommandManager.Instance.WriteOutputLine("Tangent to object snapping off");
        }
    }

    /// <summary>
    /// Toggles object quadrant snapping on and off
    /// </summary>
    public class ObjectQuadrantSnap : Command
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public ObjectQuadrantSnap()
        {
            _name = "ObjectQuadrantSnap";
            _description = "Toggles snapping of drawing line to object quadrants.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            SplinoForm.Instance.Command_ObjectQuadrantSnap();
            FinalizeCommand();
        }

        /// <summary>
        /// Outputs whether object quadrant snapping is on or off.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (SplinoForm.Instance.ObjectQuadrantSnapSelected)
                CommandManager.Instance.WriteOutputLine("Object quadrant snapping on.");
            else
                CommandManager.Instance.WriteOutputLine("Object quadrant snapping off");
        }
    }

    /// <summary>
    /// Sets the number of units between grid snaps
    /// </summary>
    public class GridSnapUnits : Command
    {
        /// <summary>
        /// Cnostructor
        /// </summary>
        public GridSnapUnits()
        {
            _name = "GridSnapUnits";
            _description = "Sets the number of units between grid snaps.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
            _usage = "Enter tne number of units between grid snaps.";
            _processingInput = true;
        }

        /// <summary>
        /// Accepts an object of varying type, casts it, and attempts to create
        /// a control point from it
        /// </summary>
        /// <param name="input">A float representing the number of units
        /// between grid snaps</param>
        /// <param name="inputs">An array of objects of varying type that will be
        /// cast and used by the command</param>
        /// <returns>True if the input was used properly</returns>
        public override bool ProcessInput(object input, object[] inputs)
        {
            bool returnVal = false;
            switch (input.GetType().Name)
            {
                case "Single":
                    float inputFloat = (float)input;
                    if (inputFloat > 0)
                    {
                        SplinoForm.Instance.GridSnapDistance = inputFloat;
                        returnVal = true;
                        FinalizeCommand();
                    }
                    break;
            }
            return returnVal;
        }

        /// <summary>
        /// Outputs the number of units between grid snaps.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            String outputLine = "Snapping to grid every " +
                SplinoForm.Instance.GridSnapDistance.ToString() +
                " unit(s).";
            CommandManager.Instance.WriteOutputLine(outputLine);
        }
    }

    /// <summary>
    /// Echoes the GridSnapUnits name and value after the 
    /// GridSnapNumeric value is changed
    /// </summary>
    public class GridSnapUnits_System : GridSnapUnits
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public GridSnapUnits_System()
            : base()
        {
            _processingInput = false;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            FinalizeCommand();
        }
    }

    /// <summary>
    /// Sets the number of degrees between angle snaps.
    /// </summary>
    public class AngleSnapDegrees : Command
    {
        /// <summary>
        /// Cnostructor
        /// </summary>
        public AngleSnapDegrees()
        {
            _name = "AngleSnapDegrees";
            _description = "Sets the number of degrees between angle snaps.";
            _undoable = false;
            _commandType = CommandType.InterfaceCommand;
            _usage = "Enter tne number of degrees between angle snaps.";
            _processingInput = true;
        }

        /// <summary>
        /// Sets the angle snap degrees to the input float.
        /// </summary>
        /// <param name="input">The angle snap degrees</param>
        /// <returns>True if the input is used successfully</returns>
        public override bool ProcessFloat(float input)
        {
            bool returnVal = false;
            if (input > 0 && input < 360)
            {
                SplinoForm.Instance.AngleSnapDegrees = input;
                returnVal = true;
                FinalizeCommand();
            }
            return returnVal;
        }

        /// <summary>
        /// Outputs the number of degrees between angle snaps.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            String outputLine = "Snapping to angle every " +
                SplinoForm.Instance.AngleSnapDegrees.ToString() +
                " degree(s).";
            CommandManager.Instance.WriteOutputLine(outputLine);
        }
    }

    /// <summary>
    /// Echoes the AngleSnapDegrees name and value after the 
    /// AngleDegreesNumeric value is changed
    /// </summary>
    public class AngleSnapDegrees_System : AngleSnapDegrees
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public AngleSnapDegrees_System()
            : base()
        {
            _processingInput = false;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            FinalizeCommand();
        }
    }

    /// <summary>
    /// Enables the user to draw a linear spline object
    /// </summary>
    public class LinearSpline : Draw
    {
        /// <summary>
        /// The newly created linear spline object
        /// </summary>
        LinearSplineObject _newLinearSpline = new LinearSplineObject();

        /// <summary>
        /// Constructor
        /// </summary>
        public LinearSpline()
        {
            _name = "LinearSpline";
            _description = "Creates a linear spline object.";
            _usage = "Enter the splines's control points below: \"x,y,z\".  Press Esc when done.";
            _undoable = true;
            _commandType = Commands.CommandType.ObjectCommand;
            _processingInput = true;
        }

        /// <summary>
        /// Adds the first control point to the new linear spline object and
        /// adds a second temporary point that is bound to the cursor
        /// </summary>
        public override void InitializeCommand()
        {
            base.InitializeCommand();
            PointObject newControlPoint = SceneManager.Instance.Command_Point_MouseDown();

            _newLinearSpline.AppendControlPoint(newControlPoint);
            SceneManager.Instance.TempSceneObject.AddSceneChild(_newLinearSpline);

            BasePoint = newControlPoint.Center;

            SplinoForm.Instance.ObjectCloseSplineSnapSelected = true;
        }

        /// <summary>
        /// Intializes the new linear spline object if it has more than two control points
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (_finalizable)
            {
                _newLinearSpline.RemoveEndPoint();
                SceneManager.Instance.TempSceneObject.SceneChildren.Remove(_newLinearSpline);
                _newLinearSpline.Initialize(SceneManager.Instance.MasterSceneObject);
                _newLinearSpline.HideControlPoints();
                _pointCursorActive = false;
                CommandManager.Instance.WriteOutputLine("\"" +
                    _newLinearSpline.Name + "\" created.");
            }
            else
            {
                _newLinearSpline.Delete();
            }

            SplinoForm.Instance.ObjectCloseSplineSnapSelected = false;
        }

        /// <summary>
        /// Deletes the linear spline object created by this command
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            _newLinearSpline.Delete();
        }

        /// <summary>
        /// Undeletes the linear spline object created by this command
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            _newLinearSpline.Undelete();
        }

        /// <summary>
        /// Mouse move event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseMove(object sender, MouseEventArgs e)
        {
            base.MouseMove(sender, e);
            if (_initialized)
            {
                _newLinearSpline.BindEndPointToDrawPoint();
            }
        }

        /// <summary>
        /// Mouse down event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                base.MouseDown(sender, e);
                PointObject newControlPoint = SceneManager.Instance.Command_Point_MouseDown();

                _newLinearSpline.AppendControlPoint(newControlPoint);

                if (!_initialized)
                    InitializeCommand();
                else if (_newLinearSpline.SceneChildren.Count > 2)
                    _finalizable = true;

                if (newControlPoint.Center == ((PointObject)_newLinearSpline.SceneChildren[0]).Center &&
                    _newLinearSpline.SceneChildren.Count > 2)
                {
                    FinalizeCommand();
                    //_newLinearSpline.CloseSpline();
                }

                BasePoint = newControlPoint.Center;
            }
        }

        /// <summary>
        /// Adds a control point to the spline based on a float that represents
        /// either the origin (0) or the distance from the last point.
        /// </summary>
        /// <param name="input">The input float to create a new control
        /// point from</param>
        /// <returns>True if the input was used properly</returns>
        public override bool ProcessFloat(float input)
        {
            if (input == 0f)
            {
                AddControlPointFromInput(new Vector3(0f, 0f, 0f));
                return true;
            }
            return false;
        }

        /// <summary>
        /// Accepts a 2D vector representing grid coordinates, and creates a 
        /// 3D vector representing world coordinates, and inserts a new control
        /// point into the spline at these 3D coordinates.
        /// </summary>
        /// <param name="input">The grid coordinates of the new control point
        /// to add</param>
        /// <returns>True if the input was properly used</returns>
        public override bool ProcessVector2(Vector2 input)
        {
            Vector3 pointCenter = 
                CommandManager.Instance.ActiveWindow.SplinoViewport.GridToWorld(input);
            AddControlPointFromInput(pointCenter);
            return true;
        }

        /// <summary>
        /// Adds a control point to the spline based on a 3D vector that represents
        /// the world coordinates of the new control point.
        /// </summary>
        /// <param name="input">A 3D vector representing the center of a new control
        /// point to add to the spline</param>
        /// <returns>True if the input vector was properly used</returns>
        public override bool ProcessVector3(Vector3 input)
        {
            AddControlPointFromInput(input);
            return true;
        }

        /// <summary>
        /// Inserts a new control point into the spline whose center is the input
        /// 3D vector.
        /// </summary>
        /// <param name="input">The center of the new control point</param>
        protected void AddControlPointFromInput(Vector3 input)
        {
            PointObject newControlPoint = SceneManager.Instance.Command_Point_Input(input);

            _newLinearSpline.InsertControlPointBeforeEnd(newControlPoint);

            if (!_initialized)
                InitializeCommand();
            else if (_newLinearSpline.SceneChildren.Count > 2)
                _finalizable = true;
            BasePoint = newControlPoint.Center;
        }
    }

    /// <summary>
    /// Enables the user to draw a non-uniform rational b-spline object
    /// </summary>
    public class NURBS : Draw
    {
        /// <summary>
        /// The newly created linear spline object
        /// </summary>
        NURBSObject _newNURBS = new NURBSObject();

        /// <summary>
        /// Constructor
        /// </summary>
        public NURBS()
        {
            _name = "NURBS";
            _description = "Creates a non-uniform rational b-spline object.";
            _usage = "Enter the splines's control points below: \"x,y,z\".  Press Esc when done.";
            _undoable = true;
            _commandType = Commands.CommandType.ObjectCommand;
            _processingInput = true;
        }

        /// <summary>
        /// Adds the first control point to the new NURBS object and
        /// adds a second temporary point that is bound to the cursor
        /// </summary>
        public override void InitializeCommand()
        {
            base.InitializeCommand();
            PointObject newControlPoint = SceneManager.Instance.Command_Point_MouseDown();

            _newNURBS.AppendControlPoint(newControlPoint);
            SceneManager.Instance.TempSceneObject.AddSceneChild(_newNURBS);

            BasePoint = newControlPoint.Center;

            SplinoForm.Instance.ObjectCloseSplineSnapSelected = true;
        }

        /// <summary>
        /// Intializes the new NURBS object if it has more than two control points
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (_finalizable)
            {
                _newNURBS.RemoveEndPoint();
                SceneManager.Instance.TempSceneObject.SceneChildren.Remove(_newNURBS);
                _newNURBS.Initialize(SceneManager.Instance.MasterSceneObject);
                _newNURBS.HideControlPoints();
                _pointCursorActive = false;
                CommandManager.Instance.WriteOutputLine("\"" +
                    _newNURBS.Name + "\" created.");
            }
            else
            {
                _newNURBS.Delete();
            }

            SplinoForm.Instance.ObjectCloseSplineSnapSelected = false;
        }

        /// <summary>
        /// Deletes the NURBS object created by this command
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            _newNURBS.Delete();
        }

        /// <summary>
        /// Undeletes the NURBS object created by this command
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            _newNURBS.Undelete();
        }

        /// <summary>
        /// Mouse move event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseMove(object sender, MouseEventArgs e)
        {
            base.MouseMove(sender, e);
            if (_initialized)
            {
                _newNURBS.BindEndPointToDrawPoint();
                //if (_newNURBS.ActiveCloseSplineSnap.ObjectSnapType == ObjectSnapType.CloseSpline && !_newNURBS.Closed)
                //    _newNURBS.CloseSpline();
                //if (_newNURBS.ActiveCloseSplineSnap.ObjectSnapType == ObjectSnapType.None && _newNURBS.Closed)
                //    _newNURBS.OpenSpline();

            }
        }

        /// <summary>
        /// Mouse down event processing for the command
        /// </summary>
        /// <param name="sender">Event initiator</param>
        /// <param name="e">Mouse event arguments</param>
        public override void MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                base.MouseDown(sender, e);
                PointObject newControlPoint = SceneManager.Instance.Command_Point_MouseDown();

                _newNURBS.AppendControlPoint(newControlPoint);

                if (!_initialized)
                    InitializeCommand();
                else if (_newNURBS.SceneChildren.Count > 2)
                    _finalizable = true;

                if (newControlPoint.Center == ((PointObject)_newNURBS.SceneChildren[0]).Center &&
                    _newNURBS.SceneChildren.Count > 2)
                {
                    FinalizeCommand();
                    //_newNURBS.CloseSpline();
                }

                BasePoint = newControlPoint.Center;
            }
        }

        /// <summary>
        /// Adds a control point to the spline based on a float that represents
        /// either the origin (0) or the distance from the last point.
        /// </summary>
        /// <param name="input">The input float to create a new control
        /// point from</param>
        /// <returns>True if the input was used properly</returns>
        public override bool ProcessFloat(float input)
        {
            if (input == 0f)
            {
                AddControlPointFromInput(new Vector3(0f, 0f, 0f));
                return true;
            }
            return false;
        }

        /// <summary>
        /// Accepts a 2D vector representing grid coordinates, and creates a 
        /// 3D vector representing world coordinates, and inserts a new control
        /// point into the spline at these 3D coordinates.
        /// </summary>
        /// <param name="input">The grid coordinates of the new control point
        /// to add</param>
        /// <returns>True if the input was properly used</returns>
        public override bool ProcessVector2(Vector2 input)
        {
            Vector3 pointCenter =
                CommandManager.Instance.ActiveWindow.SplinoViewport.GridToWorld(input);
            AddControlPointFromInput(pointCenter);
            return true;
        }

        /// <summary>
        /// Adds a control point to the spline based on a 3D vector that represents
        /// the world coordinates of the new control point.
        /// </summary>
        /// <param name="input">A 3D vector representing the center of a new control
        /// point to add to the spline</param>
        /// <returns>True if the input vector was properly used</returns>
        public override bool ProcessVector3(Vector3 input)
        {
            AddControlPointFromInput(input);
            return true;
        }

        public override void Execute()
        {
            base.Execute();
            //NURBSObject.CreateCircle();
        }

        /// <summary>
        /// Inserts a new control point into the spline whose center is the input
        /// 3D vector.
        /// </summary>
        /// <param name="input">The center of the new control point</param>
        protected void AddControlPointFromInput(Vector3 input)
        {
            PointObject newControlPoint = SceneManager.Instance.Command_Point_Input(input);

            _newNURBS.InsertControlPointBeforeEnd(newControlPoint);

            if (!_initialized)
                InitializeCommand();
            else if (_newNURBS.SceneChildren.Count > 2)
                _finalizable = true;
            BasePoint = newControlPoint.Center;
        }
    }

    /// <summary>
    /// Shows all Splino Objects in the scene that are currently hidden
    /// </summary>
    public class Show : Command
    {
        /// <summary>
        /// A list of the Splino Objects made visible by this command
        /// </summary>
        List<SplinoObject> _hiddenObjects = new List<SplinoObject>();

        /// <summary>
        /// Constructor
        /// </summary>
        public Show()
        {
            _name = "Show";
            _description = "Shows all scene objects that are currently hidden.";
            _commandType = CommandType.ObjectCommand;
            _undoable = true;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="inputObjects"></param>
        public Show(SplinoObject[] inputObjects)
            : this()
        {
            _description = "Shows scene objects that are currently hidden.";
            _inputObjects = inputObjects;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            if (_inputObjects != null)
            {
                foreach (SplinoObject splinoObject in _inputObjects)
                {
                    if (splinoObject.Hidden)
                    {
                        _hiddenObjects.Add(splinoObject);
                        splinoObject.Show();
                    }
                }
            }
            else
            {
                foreach (SplinoObject splinoObject in
                    SceneManager.Instance.MasterSceneObject.SceneChildren)
                {
                    if (splinoObject.Hidden)
                    {
                        _hiddenObjects.Add(splinoObject);
                        splinoObject.Show();
                    }
                }
            }
            _finalizable = true;
            FinalizeCommand();
        }

        /// <summary>
        /// Hides all Splino Objects that were made visibile by this command
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            foreach (SplinoObject splinoObject in _hiddenObjects)
                splinoObject.Hide();
        }

        /// <summary>
        /// Makes visible all Splino Objects that were made visible by this command
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            foreach (SplinoObject splinoObject in _hiddenObjects)
                splinoObject.Show();
        }

        /// <summary>
        /// Writes which objects were shown to the command prompt.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (_hiddenObjects.Count > 1)
                CommandManager.Instance.WriteOutputLine(
                    _hiddenObjects.Count + " objects shown.");
            else if (_hiddenObjects.Count == 1)
                CommandManager.Instance.WriteOutputLine("\"" +
                    _hiddenObjects[0].Name +
                    "\" object shown.");
        }
    }

    /// <summary>
    /// Changes the color of Splino Objects
    /// </summary>
    public class Color : Command
    {
        List<SplinoObject> _coloredObjects = new List<SplinoObject>();
        List<System.Drawing.Color> _oldColors = new List<System.Drawing.Color>();
        List<System.Drawing.Color> _newColors = new List<System.Drawing.Color>();

        /// <summary>
        /// Constructor
        /// </summary>
        public Color()
        {
            _name = "Color";
            _description = "Changes the display color of Splino Objects.";
            _usage = "Select objects to change their display color, or event their names below.";
            _commandType = CommandType.ObjectCommand;
            _undoable = true;
            if (SceneManager.Instance.SelectedObjects.Count == 0)
                _processingInput = true;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="inputObjects">The Splino Objects to change the display color of</param>
        public Color(SplinoObject[] inputObjects)
            : this()
        {
            _inputObjects = inputObjects;
        }

        /// <summary>
        /// Executes the command.
        /// </summary>
        public override void Execute()
        {
            base.Execute();

            if (_inputObjects != null)
            {
                foreach (SplinoObject splinoObject in _inputObjects)
                {
                    SplinoObjectColorDialog colorDialog =
                        new SplinoObjectColorDialog(splinoObject.Color);
                    if (colorDialog.ShowDialog() == DialogResult.OK)
                    {
                        _coloredObjects.Add(splinoObject);
                        _oldColors.Add(splinoObject.Color);
                        _newColors.Add(colorDialog.Color);
                        splinoObject.Color = colorDialog.Color;
                        _finalizable = true;
                    }
                }
            }
            else if (SceneManager.Instance.SelectedObjects.Count > 0)
            {
                foreach (SplinoObject splinoObject in SceneManager.Instance.SelectedObjects)
                {
                    SplinoObjectColorDialog colorDialog =
                        new SplinoObjectColorDialog(splinoObject.Color);
                    if (colorDialog.ShowDialog() == DialogResult.OK)
                    {
                        _coloredObjects.Add(splinoObject);
                        _oldColors.Add(splinoObject.Color);
                        _newColors.Add(colorDialog.Color);
                        splinoObject.Color = colorDialog.Color;
                        _finalizable = true;
                    }
                }
            }
            else
                return;
            SceneManager.Instance.ClearSelectedItems();
            FinalizeCommand();
        }

        /// <summary>
        /// Undoes the command.
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            for (int i = 0; i < _coloredObjects.Count; i++)
                _coloredObjects[i].Color = _oldColors[i];
        }
        
        /// <summary>
        /// Redoes the command.
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            for (int i = 0; i < _coloredObjects.Count; i++)
                _coloredObjects[i].Color = _newColors[i];
        }

        /// <summary>
        /// Accepts string names of Splino objects to change the display color of.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="inputs">An array of objects of varying type that will be
        /// cast and used by the command</param>
        /// <returns>True if the input was successfully processed</returns>
        public override bool ProcessInput(object input, object[] inputs)
        {
            foreach (Object inputObject in inputs)
            {
                try
                {
                    SplinoObject splinoObject = (SplinoObject)inputObject;
                    SplinoObjectColorDialog colorDialog =
                        new SplinoObjectColorDialog(splinoObject.Color);
                    if (colorDialog.ShowDialog() == DialogResult.OK)
                    {
                        _coloredObjects.Add(splinoObject);
                        _oldColors.Add(splinoObject.Color);
                        _newColors.Add(colorDialog.Color);
                        splinoObject.Color = colorDialog.Color;
                        _finalizable = true;
                    }
                }
                catch { }
            }
            if (_finalizable)
            {
                SceneManager.Instance.ClearSelectedItems();
                FinalizeCommand();
                return true;
            }
            return false;
        }

        /// <summary>
        /// Writes which objects had their display colors changed to the command prompt.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (_coloredObjects.Count > 1)
                CommandManager.Instance.WriteOutputLine(
                    _coloredObjects.Count + " objects display color changed.");
            else if (_coloredObjects.Count == 1)
                CommandManager.Instance.WriteOutputLine("\"" +
                    _coloredObjects[0].Name +
                    "\" object display color changed.");
        }
    }

    /// <summary>
    /// Hides all currently selected Splino Objects from the scene
    /// </summary>
    public class Hide : Command
    {
        /// <summary>
        /// A list of the Splino Objects hidden by this command
        /// </summary>
        List<SplinoObject> _hiddenObjects = new List<SplinoObject>();

        /// <summary>
        /// Constructor
        /// </summary>
        public Hide()
        {
            _name = "Hide";
            _description = "Hides Splino Objects from the scene.";
            _usage = "Select objects to hide or enter their names below.";
            _commandType = CommandType.ObjectCommand;
            _undoable = true;
            if (SceneManager.Instance.SelectedObjects.Count == 0)
                _processingInput = true;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="inputObjects">Splino Object to hide.</param>
        public Hide(SplinoObject[] inputObjects)
            : this()
        {
            _inputObjects = inputObjects;
        }

        /// <summary>
        /// Executes the command
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            if (_inputObjects != null)
            {
                foreach (SplinoObject splinoObject in _inputObjects)
                {
                    _hiddenObjects.Add(splinoObject);
                    splinoObject.Hide();
                }
            }
            else if (!_processingInput)
            {
                foreach (SplinoObject splinoObject in
                    SceneManager.Instance.SelectedObjects)
                {
                    _hiddenObjects.Add(splinoObject);
                    splinoObject.Hide();
                }
            }
            else
                return;
            SceneManager.Instance.ClearSelectedItems();
            _finalizable = true;
            FinalizeCommand();
        }

        /// <summary>
        /// Accepts string names of Splino objects to hide.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="inputs">An array of objects of varying type that will be
        /// cast and used by the command</param>
        /// <returns>True if the input was successfully processed</returns>
        public override bool ProcessInput(object input, object[] inputs)
        {
            foreach (Object inputObject in inputs)
            {
                try
                {
                    SplinoObject splinoObject = (SplinoObject)inputObject;
                    _hiddenObjects.Add(splinoObject);
                    splinoObject.Hide();
                    _finalizable = true;
                }
                catch { }
            }
            if (_finalizable)
            {
                SceneManager.Instance.ClearSelectedItems();
                FinalizeCommand();
                return true;
            } 
            return false;
        }

        /// <summary>
        /// Writes which objects were hidden to the command prompt.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (_hiddenObjects.Count > 1)
                CommandManager.Instance.WriteOutputLine(
                    _hiddenObjects.Count + " objects locked.");
            else if (_hiddenObjects.Count == 1)
                CommandManager.Instance.WriteOutputLine("\"" +
                    _hiddenObjects[0].Name +
                    "\" object hidden.");
        }

        /// <summary>
        /// Shows all Splino Objects hidden by this command
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            foreach (SplinoObject splinoObject in _hiddenObjects)
                splinoObject.Show();
        }

        /// <summary>
        /// Hides all Splino Objects originally hidden by this command
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            foreach (SplinoObject splinoObject in _hiddenObjects)
                splinoObject.Hide();
        }
    }

    /// <summary>
    /// Locks all currently selected Splino Objects, making them unselectable
    /// </summary>
    public class Lock : Command
    {
        /// <summary>
        /// A List of Splino Objects that were locked by this command
        /// </summary>
        List<SplinoObject> _lockedObjects = new List<SplinoObject>();

        /// <summary>
        /// Constructor
        /// </summary>
        public Lock()
        {
            _name = "Lock";
            _description = "Locks a Splino Object, making it unselectable.";
            _usage = "Select objects to lock or enter their names below.";
            _commandType = CommandType.ObjectCommand;
            _undoable = true;

            if (SceneManager.Instance.SelectedObjects.Count == 0)
                _processingInput = true;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="inputObjects">Splino objects to lock.</param>
        public Lock(SplinoObject[] inputObjects) : this()
        {
            _inputObjects = inputObjects;
        }

        /// <summary>
        /// Locks the selected Splino Objects
        /// </summary>
        public override void Execute()
        {
            base.Execute();

            if (_inputObjects != null)
            {
                foreach (SplinoObject splinoObject in _inputObjects)
                {
                    _lockedObjects.Add(splinoObject);
                    splinoObject.Lock();
                }
                SceneManager.Instance.ClearSelectedItems();
                _finalizable = true;
                FinalizeCommand();
            }
            else if (!_processingInput)
            {
                foreach (SplinoObject splinoObject in
                    SceneManager.Instance.SelectedObjects)
                {
                    _lockedObjects.Add(splinoObject);
                    splinoObject.Lock();
                }
                SceneManager.Instance.ClearSelectedItems();
                _finalizable = true;
                FinalizeCommand();
            }
            else
                InitializeCommand();
        }

        /// <summary>
        /// Unlocks the Splino Objects that were locked by this command
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            foreach (SplinoObject splinoObject in _lockedObjects)
                splinoObject.Unlock();
        }

        /// <summary>
        /// Relocks the Splino Objects that were originally locked by this command
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            foreach (SplinoObject splinoObject in _lockedObjects)
                splinoObject.Lock();
        }

        /// <summary>
        /// Accepts string names of Splino objects to lock.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="inputs">An array of objects of varying type that will be
        /// cast and used by the command</param>
        /// <returns>True if the input was successfully processed</returns>
        public override bool ProcessInput(object input, object[] inputs)
        {
            foreach (Object inputObject in inputs)
            {
                try
                {
                    SplinoObject splinoObject = (SplinoObject)inputObject;
                    _lockedObjects.Add(splinoObject);
                    splinoObject.Lock();
                    _finalizable = true;
                }
                catch { }
            }
            if (_finalizable)
            {
                SceneManager.Instance.ClearSelectedItems();
                FinalizeCommand();
                return true;
            } 
            return false;
        }

        /// <summary>
        /// Writes which objects were locked to the command prompt.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (_lockedObjects.Count > 1)
                CommandManager.Instance.WriteOutputLine(
                    _lockedObjects.Count + " objects locked.");
            else if (_lockedObjects.Count == 1)
                CommandManager.Instance.WriteOutputLine("\"" +
                    _lockedObjects[0].Name +
                    "\" object locked.");
        }
    }

    /// <summary>
    /// Unlocks all locked Splino Objects, making them selectable
    /// </summary>
    public class Unlock : Command
    {
        /// <summary>
        /// A list of Splino Objects that were unlocked by this command
        /// </summary>
        List<SplinoObject> _lockedObjects = new List<SplinoObject>();

        /// <summary>
        /// Constructor
        /// </summary>
        public Unlock()
        {
            _name = "Unlock";
            _description = "Unlocks all locked Splino Objects, making them selectable.";
            _usage = "Select objects to unlock or enter their names below.";
            _commandType = CommandType.ObjectCommand;
            _undoable = true;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="inputObjects">Splino objects to unlock.</param>
        public Unlock(SplinoObject[] inputObjects)
            : this()
        {
            _description = "Unlocks a Splino Objects, making them selectable.";
            _inputObjects = inputObjects;
        }

        /// <summary>
        /// Unlocks all locked Splino Objects in the scene
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            if (_inputObjects != null)
            {
                foreach (SplinoObject splinoObject in _inputObjects)
                {
                    if (splinoObject.Locked)
                    {
                        _lockedObjects.Add(splinoObject);
                        splinoObject.Unlock();
                    }
                }
            }
            else
            {
                foreach (SplinoObject splinoObject in
                    SceneManager.Instance.MasterSceneObject.SceneChildren)
                {
                    if (splinoObject.Locked)
                    {
                        _lockedObjects.Add(splinoObject);
                        splinoObject.Unlock();
                    }
                }
            }
            _finalizable = true;
            FinalizeCommand();

        }

        /// <summary>
        /// Locks all Splino Objects that were unlocked by this command
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            foreach (SplinoObject splinoObject in _lockedObjects)
                splinoObject.Lock();
        }

        /// <summary>
        /// Unlocks all Splino Objects that were originally unlocked by this command
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            foreach (SplinoObject splinoObject in _lockedObjects)
                splinoObject.Unlock();
        }

        /// <summary>
        /// Accepts string names of Splino objects to lock.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="inputs">An array of objects of varying type that will be
        /// cast and used by the command</param>
        /// <returns>True if the input was successfully processed</returns>
        public override bool ProcessInput(object input, object[] inputs)
        {
            foreach (Object inputObject in inputs)
            {
                try
                {
                    SplinoObject splinoObject = (SplinoObject)inputObject;
                    _lockedObjects.Add(splinoObject);
                    splinoObject.Unlock();
                    _finalizable = true;
                }
                catch { }
            }
            if (_finalizable)
            {
                SceneManager.Instance.ClearSelectedItems();
                FinalizeCommand();
                return true;
            }
            return false;
        }


        /// <summary>
        /// Writes which objects were locked to the command prompt.
        /// </summary>
        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (_lockedObjects.Count > 1)
                CommandManager.Instance.WriteOutputLine(
                    SceneManager.Instance.SelectedObjects.Count +
                    " objects unlocked.");
            else if (_lockedObjects.Count == 1)
                CommandManager.Instance.WriteOutputLine("\"" +
                    _lockedObjects[0].Name +
                    "\" object unlocked.");
            else
                CommandManager.Instance.WriteOutputLine("No objects are currently locked.");
        }
    }

    /// <summary>
    /// Hides the control points of all Spline Objects in the scene that currently
    /// have visible control points
    /// </summary>
    public class HideControlPoints : Command
    {
        // A List of Spline Objects whose control points were hidden by this command
        List<SplineObject> _splineObjects = new List<SplineObject>();

        /// <summary>
        /// Constructor
        /// </summary>
        public HideControlPoints()
        {
            _name = "HideControlPoints";
            _description = "Hides the control points of all Spline Objects";
            _usage = "Select splines or enter their names below.";
            _commandType = CommandType.ObjectCommand;
            _undoable = true;
        }

        /// <summary>
        /// Hides the control points for each Spline Object in the scene
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            foreach (SplinoObject splinoObject in
                SceneManager.Instance.MasterSceneObject.SceneChildren)
            {
                try 
                {
                    SplineObject splineObject = (SplineObject)splinoObject;
                    if (!splineObject.ControlPointsHidden)
                        splineObject.HideControlPoints();
                    _splineObjects.Add(splineObject);
                }
                catch
                {}
            }
            _finalizable = true;
            FinalizeCommand();
        }

        /// <summary>
        /// Shows the control points for each Spline Object whose control
        /// points were originally hidden by this command
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            foreach (SplineObject splineObject in _splineObjects)
                splineObject.ShowControlPoints();
        }

        /// <summary>
        /// Hides the control points for each Spline Object whose control
        /// points were originally hidden by this command
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            foreach (SplineObject splineObjject in _splineObjects)
                splineObjject.HideControlPoints();
        }
    }

    /// <summary>
    /// Turns on control point visibility for each selected spline object
    /// </summary>
    public class ShowControlPoints : Command
    {
        /// <summary>
        /// A List of Spline Object whose control points were made visible by this command
        /// </summary>
        List<SplineObject> _splineObjects = new List<SplineObject>();

        /// <summary>
        /// Constructor
        /// </summary>
        public ShowControlPoints()
        {
            _name = "ShowControlPoints";
            _description = "Shows the control points of currently selected spline objects.";
            _usage = "Select splines or enter their names below.";
            _commandType = CommandType.ObjectCommand;
            _undoable = true;
        }

        /// <summary>
        /// Shows the control points for each selected Spline Object
        /// </summary>
        public override void Execute()
        {
            base.Execute();
            foreach (SplinoObject splinoObject in
                SceneManager.Instance.SelectedObjects)
            {
                try
                {
                    SplineObject splineObject = (SplineObject)splinoObject;
                    if (splineObject.ControlPointsHidden)
                        splineObject.ShowControlPoints();
                    _splineObjects.Add(splineObject);
                }
                catch { }
            }
            _finalizable = true;
            FinalizeCommand();
        }

        /// <summary>
        /// Hides the control points for each Spline Object whose control
        /// points were originally made visible by this command
        /// </summary>
        public override void Undo()
        {
            base.Undo();
            foreach (SplineObject splineObject in _splineObjects)
                splineObject.HideControlPoints();
        }

        /// <summary>
        /// Shows the control points for each Spline Object whose control
        /// points were originally made visible by this command
        /// </summary>
        public override void Redo()
        {
            base.Redo();
            foreach (SplineObject splineObjject in _splineObjects)
                splineObjject.ShowControlPoints();
        }
    }

    public class Move_System : Move
    {
        public Move_System()
        {
            _name = "Move";
            _description = "Moves Splino Objects from one point to another.";
            _usage = "Select objects to move or enter their names below.";
            _commandType = CommandType.SystemCommand;
            _undoable = true;
        }

        public override void MouseUp(object sender, MouseEventArgs e)
        {
            base.MouseUp(sender, e);
            _finalizable = true;
            FinalizeCommand();
        }
    }

    public class Move : Draw
    {
        List<SplinoObject> _splinoObjects = new List<SplinoObject>();
        LinearSplineObject _moveSpline = new LinearSplineObject();
        Vector3 _translation = Vector3.Zero;
        Vector3 _startPoint;

        public Move()
        {
            _name = "Move";
            _description = "Moves Splino Objects from one point to another.";
            _usage = "Select objects to move or enter their names below.";
            _commandType = CommandType.ObjectCommand;
            _undoable = true;
            if (SceneManager.Instance.SelectedObjects.Count == 0)
                _processingInput = true;
        }

        public Move(SplinoObject[] inputObjects)
            : this()
        {
            _inputObjects = inputObjects;
        }

        public override void Execute()
        {
            base.Execute();
            if (_inputObjects != null)
            {
                foreach (SplinoObject splinoObject in _inputObjects)
                    _splinoObjects.Add(splinoObject);
            }
            else if (!_processingInput)
            {
                foreach (SplinoObject splinoObject in
                    SceneManager.Instance.SelectedObjects)
                    _splinoObjects.Add(splinoObject);
            }
            else
                return;
        }

        public override void InitializeCommand()
        {
            base.InitializeCommand();
            PointObject newControlPoint = SceneManager.Instance.Command_Point_MouseDown();

            _moveSpline.AppendControlPoint(newControlPoint);
            SceneManager.Instance.TempSceneObject.AddSceneChild(_moveSpline);

            BasePoint = newControlPoint.Center;

            SplinoForm.Instance.ObjectCloseSplineSnapSelected = true;
        }

        public override void FinalizeCommand()
        {
            base.FinalizeCommand();
            if (_finalizable)
            {
                foreach (SplinoObject splinoObject in _splinoObjects)
                    splinoObject.FinalizeTransform();
                _moveSpline.RemoveEndPoint();
                SceneManager.Instance.TempSceneObject.SceneChildren.Remove(_moveSpline);

                _pointCursorActive = false;
                if (_splinoObjects.Count > 1)
                {
                    CommandManager.Instance.WriteOutputLine("\"" +
                        _splinoObjects.Count + "\" objects moved " + _translation.X + ", " + _translation.Y + ", " + _translation.Z + " units.");
                }
                else
                {
                    CommandManager.Instance.WriteOutputLine("\"" +
                        _splinoObjects[0].Name + "\" moved " + _translation.X + ", " + _translation.Y + ", " + _translation.Z + " units.");
                }
            }

            _moveSpline.Delete();

            SplinoForm.Instance.ObjectCloseSplineSnapSelected = false;
        }

        public override void Undo()
        {
            base.Undo();
            foreach (SplinoObject splinoObject in _splinoObjects)
            {
                splinoObject.Translate(-_translation);
                splinoObject.FinalizeTransform();
            }
        }

        public override void Redo()
        {
            base.Redo();
            foreach (SplinoObject splinoObject in _splinoObjects)
            {
                splinoObject.Translate(_translation);
                splinoObject.FinalizeTransform();
            }
        }

        public override void MouseMove(object sender, MouseEventArgs e)
        {
            base.MouseMove(sender, e);
            if (_initialized)
            {
                foreach (SplinoObject splinoObject in _splinoObjects)
                    splinoObject.Move(-_translation);

                PointObject endPoint = (PointObject)_moveSpline.SceneChildren[1];
                PointObject startPoint = (PointObject)_moveSpline.SceneChildren[0];

                _translation = endPoint.Center - startPoint.Center;

                foreach (SplinoObject splinoObject in _splinoObjects)
                    splinoObject.Move(_translation);

                _moveSpline.BindEndPointToDrawPoint();
            }
        }

 
        public override void MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                base.MouseDown(sender, e);
                PointObject newControlPoint = SceneManager.Instance.Command_Point_MouseDown();

                _moveSpline.AppendControlPoint(newControlPoint);

                if (!_initialized)
                    InitializeCommand();
                else if (_moveSpline.SceneChildren.Count == 3)
                {
                    _finalizable = true;
                    FinalizeCommand();
                }

                BasePoint = newControlPoint.Center;
            }
        }

        public override bool ProcessFloat(float input)
        {
            if (input == 0f)
            {
                AddControlPointFromInput(new Vector3(0f, 0f, 0f));
                return true;
            }
            return false;
        }

        public override bool ProcessVector2(Vector2 input)
        {
            Vector3 pointCenter =
                CommandManager.Instance.ActiveWindow.SplinoViewport.GridToWorld(input);
            AddControlPointFromInput(pointCenter);
            return true;
        }

        public override bool ProcessVector3(Vector3 input)
        {
            AddControlPointFromInput(input);
            return true;
        }


        protected void AddControlPointFromInput(Vector3 input)
        {
            PointObject newControlPoint = SceneManager.Instance.Command_Point_Input(input);

            _moveSpline.InsertControlPointBeforeEnd(newControlPoint);

            if (!_initialized)
                InitializeCommand();
            else if (_moveSpline.SceneChildren.Count == 3)
            {
                _finalizable = true;
                FinalizeCommand();
            }
            BasePoint = newControlPoint.Center;
        }
    }

    public class Scale1D : Draw
    {
        protected List<SplinoObject> _splinoObjects = new List<SplinoObject>();
        protected LinearSplineObject _scaleSpline = new LinearSplineObject();
        protected Vector3 _scale = new Vector3(1);
        protected Vector3 _startPoint;

        public Scale1D()
        {
            _name = "Scale1D";
            _description = "Scales Splino Objects in one direction.";
            _usage = "Select objects to scale or enter their names below.";
            _commandType = CommandType.ObjectCommand;
            _undoable = true;
            if (SceneManager.Instance.SelectedObjects.Count == 0)
                _processingInput = true;
        }

        public Scale1D(SplinoObject[] inputObjects)
            : this()
        {
            _inputObjects = inputObjects;
        }

        public override void Execute()
        {
            base.Execute();
            if (_inputObjects != null)
            {
                foreach (SplinoObject splinoObject in _inputObjects)
                    _splinoObjects.Add(splinoObject);
            }
            else if (!_processingInput)
            {
                foreach (SplinoObject splinoObject in
                    SceneManager.Instance.SelectedObjects)
                    _splinoObjects.Add(splinoObject);
            }
            else
                return;
        }

        public override void InitializeCommand()
        {
            base.InitializeCommand();
            PointObject newControlPoint = SceneManager.Instance.Command_Point_MouseDown();

            _scaleSpline.AppendControlPoint(newControlPoint);
            SceneManager.Instance.TempSceneObject.AddSceneChild(_scaleSpline);

            BasePoint = newControlPoint.Center;

            SplinoForm.Instance.ObjectCloseSplineSnapSelected = true;
        }

        public override void FinalizeCommand()
        {
            base.FinalizeCommand();

            SceneManager.Instance.CursorPointLinearConstraintStart = null;
            SceneManager.Instance.CursorPointLinearConstraintEnd = null;
            if (_finalizable)
            {
                foreach (SplinoObject splinoObject in _splinoObjects)
                    splinoObject.FinalizeTransform();

                _scaleSpline.RemoveEndPoint();
                SceneManager.Instance.TempSceneObject.SceneChildren.Remove(_scaleSpline);

                _pointCursorActive = false;
                if (_splinoObjects.Count > 1)
                {
                    CommandManager.Instance.WriteOutputLine("\"" +
                        _splinoObjects.Count + "\" objects moved " + _scale.X + ", " + _scale.Y + ", " + _scale.Z + " units.");
                }
                else
                {
                    CommandManager.Instance.WriteOutputLine("\"" +
                        _splinoObjects[0].Name + "\" moved " + _scale.X + ", " + _scale.Y + ", " + _scale.Z + " units.");
                }
            }

            _scaleSpline.Delete();

            SplinoForm.Instance.ObjectCloseSplineSnapSelected = false;
        }

        public override void Undo()
        {
            base.Undo();
            foreach (SplinoObject splinoObject in _splinoObjects)
                splinoObject.Scale(new Vector3(1/_scale.X, 1/_scale.Y, 1/_scale.Z));
        }

        public override void Redo()
        {
            base.Redo();
            foreach (SplinoObject splinoObject in _splinoObjects)
                splinoObject.Scale(_scale);
        }

        public override void MouseMove(object sender, MouseEventArgs e)
        {
            base.MouseMove(sender, e);
            if (_initialized)
            {
                if (_scaleSpline.SceneChildren.Count > 2)
                {
                    foreach (SplinoObject splinoObject in _splinoObjects)
                        splinoObject.ResetTransform();

                    PointObject endPoint = (PointObject)_scaleSpline.SceneChildren[2];
                    PointObject midPoint = (PointObject)_scaleSpline.SceneChildren[1];
                    PointObject startPoint = (PointObject)_scaleSpline.SceneChildren[0];
                    float startDot = Vector3.Dot(midPoint.Center - startPoint.Center, midPoint.Center - startPoint.Center);
                    float endDot = Vector3.Dot(midPoint.Center - startPoint.Center, endPoint.Center - startPoint.Center);
                    float scale = endDot / startDot;
                    foreach (SplinoObject splinoObject in _splinoObjects)
                    {
                        splinoObject.Translate(-startPoint.Center);
                        splinoObject.Rotate(SplinoMath.RotationQuatFromVectors(Vector3.Normalize(midPoint.Center - startPoint.Center), Vector3.UnitY));
                        splinoObject.Scale(new Vector3(1, scale, 1));
                        splinoObject.Rotate(SplinoMath.RotationQuatFromVectors(Vector3.UnitY, Vector3.Normalize(midPoint.Center - startPoint.Center)));
                        splinoObject.Translate(startPoint.Center);
                    }
                }
                _scaleSpline.BindEndPointToDrawPoint();
            }
        }


        public override void MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                base.MouseDown(sender, e);
                PointObject newControlPoint = SceneManager.Instance.Command_Point_MouseDown();

                _scaleSpline.AppendControlPoint(newControlPoint);

                if (!_initialized)
                    InitializeCommand();
                else if (_scaleSpline.SceneChildren.Count == 3)
                {
                    SceneManager.Instance.CursorPointLinearConstraintStart = ((PointObject)_scaleSpline.SceneChildren[0]).Center;
                    SceneManager.Instance.CursorPointLinearConstraintEnd = ((PointObject)_scaleSpline.SceneChildren[1]).Center;
                }
                else if (_scaleSpline.SceneChildren.Count == 4)
                {
                    _finalizable = true;
                    FinalizeCommand();
                }

                BasePoint = newControlPoint.Center;
            }
        }

        public override bool ProcessFloat(float input)
        {
            if (input == 0f)
            {
                AddControlPointFromInput(new Vector3(0f, 0f, 0f));
                return true;
            }
            return false;
        }

        public override bool ProcessVector2(Vector2 input)
        {
            Vector3 pointCenter =
                CommandManager.Instance.ActiveWindow.SplinoViewport.GridToWorld(input);
            AddControlPointFromInput(pointCenter);
            return true;
        }

        public override bool ProcessVector3(Vector3 input)
        {
            AddControlPointFromInput(input);
            return true;
        }

        protected void AddControlPointFromInput(Vector3 input)
        {
            PointObject newControlPoint = SceneManager.Instance.Command_Point_Input(input);

            _scaleSpline.InsertControlPointBeforeEnd(newControlPoint);

            if (!_initialized)
                InitializeCommand();
            else if (_scaleSpline.SceneChildren.Count == 3)
            {
                _finalizable = true;
                FinalizeCommand();
            }
            BasePoint = newControlPoint.Center;
        }
    }

    public class Scale2D : Scale1D
    {
        public Scale2D()
        {
            _name = "Scale2D";
            _description = "Scales Splino Objects in two directions relative to the viewport's grid.";
            _usage = "Select objects to scale or enter their names below.";
            _commandType = CommandType.ObjectCommand;
            _undoable = true;
            if (SceneManager.Instance.SelectedObjects.Count == 0)
                _processingInput = true;
        }

        public Scale2D(SplinoObject[] inputObjects)
            : this()
        {
            _inputObjects = inputObjects;
        }

        public override void MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                base.MouseDown(sender, e);
                PointObject newControlPoint = SceneManager.Instance.Command_Point_MouseDown();

                _scaleSpline.AppendControlPoint(newControlPoint);

                if (!_initialized)
                    InitializeCommand();
                else if (_scaleSpline.SceneChildren.Count == 4)
                {
                    _finalizable = true;
                    FinalizeCommand();
                }

                BasePoint = newControlPoint.Center;
            }
        }

        public override void MouseMove(object sender, MouseEventArgs e)
        {
            base.MouseMove(sender, e);
            if (_initialized)
            {
                if (_scaleSpline.SceneChildren.Count > 2)
                {
                    foreach (SplinoObject splinoObject in _splinoObjects)
                        splinoObject.ResetTransform();

                    PointObject endPoint = (PointObject)_scaleSpline.SceneChildren[2];
                    PointObject midPoint = (PointObject)_scaleSpline.SceneChildren[1];
                    PointObject startPoint = (PointObject)_scaleSpline.SceneChildren[0];
                    float scale = (endPoint.Center - startPoint.Center).LengthSquared() / (midPoint.Center - startPoint.Center).LengthSquared();

                    foreach (SplinoObject splinoObject in _splinoObjects)
                    {
                        splinoObject.Translate(-startPoint.Center);

                        splinoObject.Rotate(SplinoMath.RotationQuatFromVectors(Vector3.Normalize(midPoint.Center - startPoint.Center), Vector3.UnitY));
                        splinoObject.Scale(new Vector3(1, scale, 1));
                        splinoObject.Rotate(SplinoMath.RotationQuatFromVectors(Vector3.UnitY, Vector3.Normalize(midPoint.Center - startPoint.Center)));

                        splinoObject.Rotate(SplinoMath.RotationQuatFromVectors(Vector3.Normalize(midPoint.Center - startPoint.Center), Vector3.UnitX));
                        splinoObject.Scale(new Vector3(scale, 1, 1));
                        splinoObject.Rotate(SplinoMath.RotationQuatFromVectors(Vector3.UnitX, Vector3.Normalize(midPoint.Center - startPoint.Center)));

                        splinoObject.Translate(startPoint.Center);
                    }
                }
                _scaleSpline.BindEndPointToDrawPoint();
            }
        }
    }
}

